- 通过队列实现广度优先遍历,即层序遍历,找到目标节点,返回目标节点到根节点的最短路径长度
- 如果在第 k 轮中将结点
X
添加到队列中,则根结点与X
之间的最短路径的长度恰好是k
。也就是说,第一次找到目标结点时,你已经处于最短路径中- 我们首先将根结点排入队列。然后在每一轮中,我们逐个处理已经在队列中的结点,并将所有邻居添加到队列中。值得注意的是,新添加的节点不会立即遍历,而是在下一轮中处理
- 结点的处理顺序与它们添加到队列的顺序是完全相同的顺序,即先进先出(FIFO)。这就是我们在 BFS 中使用队列的原因
力扣https://leetcode-cn.com/leetbook/read/queue-stack/kc5ge/
模板代码 一
- 首先将根顶点入队
- 然后遍历当前队列的所有顶点,这个时候只有一个根顶点
- 然后将所有邻接点入队
- 然后根顶点出队,
- 然后循环进行下一轮
- 这个和模板代码三类似,但是又不同,感觉模版三更精简,只有2层循环
package com.company.myQueue;
import java.util.ArrayDeque;
import java.util.Deque;
public class BFSQueue {
/**
* 返回目标节点和根节点之间的长度
*/
int BFS(Node root, Node target) {
// store all nodes which are waiting to be processed
Deque<Node> queue = new ArrayDeque<>();
// number of steps neeeded from root to current node
int step = 0;
// initialize
queue.offer(root);
// BFS
while (!queue.isEmpty()) {
step = step + 1;
// iterate the nodes which are already in the queue
int size = queue.size();
for (int i = 0; i < size; ++i) {
Node cur = queue.poll();
if (cur.value == target.value) {
return step;
}
//示 cur节点的所有孩子节点放到队列中
for (Node next : cur.childrenNode) {
queue.offer(next);
}
//removeFirst() 等价 queue.poll()
queue.removeFirst();
}
}
// there is no path from root to target
return -1;
}
}
模板代码二
- 有时,确保我们永远
不会访问一个结点两次
很重要。否则,我们可能陷入无限循环。如果是这样,我们可以在上面的代码中添加一个哈希集来解决这个问题 -
有两种情况你不需要使用哈希集
-
你完全确定没有循环,例如,在树遍历中;
-
你确实希望多次将结点添加到队列中。
-
public class BFSQueue2 {
/**
* 返回目标节点和根节点之间的长度
*/
int BFS(Node root, Node target) {
// store all nodes which are waiting to be processed
Queue<Node> queue = new ConcurrentLinkedQueue<>();
// store all the used nodes
Set<Node> used = new HashSet<>();
// number of steps neeeded from root to current node
int step = 0;
// initialize
queue.offer(root);
used.add(root);
// BFS
while (!queue.isEmpty()) {
step = step + 1;
// iterate the nodes which are already in the queue
int size = queue.size();
for (int i = 0; i < size; ++i) {
Node cur = queue.poll();
if (cur.value == target.value) {
return step;
}
for (Node next : cur.childrenNode) {
if (!used.contains(next)) {
queue.offer(root);
used.add(root);
}
}
queue.poll();
}
}
// there is no path from root to target
return -1;
}
}
模板代码 三
- 首先访问根顶点,访问完了要出队
- 然后再将根顶点的所有邻接点入队列,并没有访问
- 然后下一此循环依次访问每个邻接点
- 重复第1步
核心总结
- 两层循环
- 第一层循环访问一层的顶点
- 第二层循环将当前顶点的邻接点放入队列
package com.company.myQueue;
import java.util.*;
public class Solution7 {
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(Node root, int target) {
Set<Node> visited = new HashSet<>();
Queue<Node> queue = new ArrayDeque<>();
//入栈类比函数入栈
queue.offer(root);
//这的循环一次就是一次函数调用
while (!queue.isEmpty()) {
Node cur = queue.peek();
if (cur.value == target) {
return true;
}
for (Node next : cur.childrenNode) {
if (!visited.contains(next)) {
queue.offer(next);
visited.add(next);
}
}
queue.poll();
}
return false;
}
}
BFS 用队列 实现
BFS 用队列 实现
BFS 用队列 实现
没得会员看看别人的答案