您的位置:首页 > 其它

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

2014-09-12 11:14 393 查看
我们知道,在图论算法中,求最短路是最基本的问题。在求最短路的问题中,应用双向广度优先搜索算法,又是一个较为高效而又简单的算法。所谓双向广度优先搜索,其实根本的核心还是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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息