首页 > 代码库 > 图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)

图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)

我们知道,在图论算法中,求最短路是最基本的问题。在求最短路的问题中,应用双向广度优先搜索算法,又是一个较为高效而又简单的算法。所谓双向广度优先搜索,其实根本的核心还是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)