Q.双向BFS是否真的能提高效率?
假设单向BFS需要搜索 N 层才能到达终点,每层的判断量为 X,那么总的运算量为X ^ N. 如果换成是双向BFS,前后各自需要搜索 N / 2 层,总运算量为2 * X ^ {N / 2}。如果 N 比较大且X 不为 1,则运算量相较于单向BFS可以大大减少,差不多可以减少到原来规模的根号的量级。
参考代码
/**
* Definition for graph node.
* class UndirectedGraphNode {
* int label;
* ArrayList<UndirectedGraphNode> neighbors;
* UndirectedGraphNode(int x) {
* label = x; neighbors = new ArrayList<UndirectedGraphNode>();
* }
* };
*/
public int doubleBFS(UndirectedGraphNode start, UndirectedGraphNode end) {
if (start.equals(end)) {
return 1;
}
// 起点开始的BFS队列
Queue<UndirectedGraphNode> startQueue = new LinkedList<>();
// 终点开始的BFS队列
Queue<UndirectedGraphNode> endQueue = new LinkedList<>();
startQueue.add(start);
endQueue.add(end);
int step = 0;
// 记录从起点开始访问到的节点
Set<UndirectedGraphNode> startVisited = new HashSet<>();
// 记录从终点开始访问到的节点
Set<UndirectedGraphNode> endVisited = new HashSet<>();
startVisited.add(start);
endVisited.add(end);
while (!startQueue.isEmpty() || !endQueue.isEmpty()) {
int startSize = startQueue.size();
int endSize = endQueue.size();
// 按层遍历
step ++;
for (int i = 0; i < startSize; i ++) {
UndirectedGraphNode cur = startQueue.poll();
for (UndirectedGraphNode neighbor : cur.neighbors) {
if (startVisited.contains(neighbor)) {//重复节点
continue;
} else if (endVisited.contains(neighbor)) {//相交
return step;
} else {
startVisited.add(neighbor);
startQueue.add(neighbor);
}
}
}
step ++;
for (int i = 0; i < endSize; i ++) {
UndirectedGraphNode cur = endQueue.poll();
for (UndirectedGraphNode neighbor : cur.neighbors) {
if (endVisited.contains(neighbor)) {
continue;
} else if (startVisited.contains(neighbor)) {
return step;
} else {
endVisited.add(neighbor);
endQueue.add(neighbor);
}
}
}
}
return -1; // 不连通
}
Dummy Node,翻译为哨兵节点。Dummy Node 一般本身不存储任何实际有意义的值,通常用作"占位",或者链表的“虚拟头”。
如很多的链表问题中,我们会在原来的头head的前面新增一个节点,这个节点没有任何值,但是 next 指向 head。这样就会方便对 head 进行删除或者在前面插入等操作。
// T 表示任意你想存储的类型
Queue<T> queue1 = new LinkedList<>();
Queue<T> queue2 = new LinkedList<>();
queue1.offer(startNode);
int currentLevel = 0;
while (!queue1.isEmpty()) {
int size = queue1.size();
for (int i = 0; i < size; i++) {
T head = queue1.poll();
for (all neighbors of head) {
queue2.offer(neighbor);
}
}
Queue<T> temp = queue1;
queue1 = queue2;
queue2 = temp;
queue2.clear();
currentLevel++;
}