我们知道,在图论算法中,求最短路是最基本的问题。在求最短路的问题中,应用双向广度优先搜索算法,又是一个较为高效而又简单的算法。所谓双向广度优先搜索,其实根本的核心还是BFS,只不过它是从起点和终点两头同时搜索,大大提高了搜索效率,又节省了搜索空间。广搜大家知道当然是用队列来实现了,在这里,要注意的问题就是,我们必须按层搜索,正向队列处理一层,接着去处理反向队列的一层,按层交替进行,而不是按节点交替进行,这点需要注意,其他的也就很简单了,代码中附有注释,如有问题请留言。
package similarity; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.Set; public class ShortestStep { Map<Integer, LinkedList<Integer>> graph; Map<String, Integer> graphmapping; public ShortestStep(String path) {//构造函数里初始化,构造无向图 String[] strs; String str; int a, b; try { BufferedReader br = new BufferedReader(new FileReader(path)); graph = new HashMap<Integer, LinkedList<Integer>>(); while ((str = br.readLine()) != null) { strs = str.split("\\s"); a = Integer.parseInt(strs[0]); b = Integer.parseInt(strs[1]); if (graph.containsKey(a)) { graph.get(a).add(b); } else { LinkedList<Integer> linkedlist = new LinkedList<Integer>(); linkedlist.add(b); graph.put(a, linkedlist); } if (graph.containsKey(b)) { graph.get(b).add(a); } else { LinkedList<Integer> linkedlist = new LinkedList<Integer>(); linkedlist.add(a); graph.put(b, linkedlist); } } br.close(); } catch (IOException e) { e.printStackTrace(); } } public void initialMapping(String path) {/*此函数为备用,若想查询dbpedia数据集上URI之间的最短路,可用此初始化函数加载映射文件*/ String[] strs; String str; graphmapping = new HashMap<String, Integer>(); try { BufferedReader br = new BufferedReader(new FileReader(path)); while ((str = br.readLine()) != null) { strs = str.split("\\s"); int t = Integer.parseInt(strs[1]); graphmapping.put(strs[0], t); } br.close(); } catch (IOException e) { e.printStackTrace(); } } public void findShortestStep(int a, int b) {/*双向广度优先搜索*/ Queue<Integer> queue1 = new LinkedList<Integer>();//正向队列 Queue<Integer> queue2 = new LinkedList<Integer>();//反向队列 Queue<Integer> adj1;//记录邻接点 Queue<Integer> adj2; Set<Integer> visit1 = new HashSet<Integer>();//标记是否访问 Set<Integer> visit2 = new HashSet<Integer>(); Map<Integer, Integer> step1 = new HashMap<Integer, Integer>();//记录步数 Map<Integer, Integer> step2 = new HashMap<Integer, Integer>(); queue1.add(a); queue2.add(b); visit1.add(a); visit2.add(b); step1.put(a, 0); step2.put(b, 0); int cnt1 = 0;//用来记录搜索的层数 int cnt2 = 0; while (!queue1.isEmpty() || !queue2.isEmpty()) { while (true) { Integer nextnode1 = queue1.peek(); adj1 = graph.get(nextnode1); if(step1.get(nextnode1)!=cnt1){ //按层搜索,正向队列搜一层,反向队列搜一层,交替进行, //如果当前出队点的层数超过正在搜索的层数,则跳出循环,去反向队列搜索 break; } queue1.poll(); if (adj1 != null) { Iterator<Integer> itadj1 = adj1.iterator(); while (itadj1.hasNext()) { Integer neighbor1 = itadj1.next(); if (!visit1.contains(neighbor1)) { if (visit2.contains(neighbor1)) {//如果有共同的节点出现,则说明最短路找到,输出即可 System.out.println(step2.get(neighbor1) + step1.get(nextnode1) + 1); return; } else { queue1.add(neighbor1); visit1.add(neighbor1); step1.put(neighbor1, step1.get(nextnode1) + 1); } } } } } cnt1++; while (true) { Integer nextnode2 = queue2.peek(); adj2 = graph.get(nextnode2); if(step2.get(nextnode2)!=cnt2){ //按层搜索,正向队列搜一层,反向队列搜一层,交替进行, //如果当前出队点的层数超过正在搜索的层数,则跳出循环,去正向队列搜索 break; } queue2.poll(); if (adj2 != null) { Iterator<Integer> itadj2 = adj2.iterator(); while (itadj2.hasNext()) { Integer neighbor2 = itadj2.next(); if (!visit2.contains(neighbor2)) { if (visit1.contains(neighbor2)) {//如果有共同的节点出现,则说明最短路找到,输出即可 System.out.println(step1.get(neighbor2) + step2.get(nextnode2) + 1); return; } else { queue2.add(neighbor2); visit2.add(neighbor2); step2.put(neighbor2, step2.get(nextnode2) + 1); } } } } } cnt2++; } } public static void main(String[] args) { ShortestStep ss = new ShortestStep("c:/datatest.txt"); ss.findShortestStep(6, 7); } }
图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)
原文地址:http://blog.csdn.net/yangxiangyuibm/article/details/39227447