广度优先搜索(Breadth-First Search,BFS)是一种图形搜索算法,用于遍历或搜索树或图。它从根节点开始,沿着树的宽度遍历树的节点,即先访问所有相邻的节点,然后再访问下一层的节点。这种搜索策略保证了从起始节点到任何其他节点的最短路径最先被找到。
BFS由Edward F. Moore在1959年提出,是图论中另一个基础而重要的算法。
在图或树数据结构中按层级顺序系统地访问所有节点,确保每个节点恰好被访问一次,并能找到从起始节点到任意节点的最短路径。
基于图论、队列数据结构和最短路径理论的数学概念。
从起始节点开始,首先访问所有与起始节点直接相连的节点,然后依次访问这些节点的未访问邻居节点,按层级逐层扩展,直到所有节点都被访问。
- 创建一个队列,将起始节点加入队列并标记为已访问;
- 当队列不为空时,从队列中取出一个节点;
- 访问该节点;
- 将该节点所有未访问的邻居节点加入队列并标记为已访问;
- 重复步骤2-4,直到队列为空。
算法 BFS(graph, startVertex)
输入:图graph,起始顶点startVertex
输出:节点的访问顺序
创建一个队列queue
创建一个集合visited用于记录已访问的节点
将startVertex加入queue和visited
while queue不为空
vertex = 从queue中取出队首元素
访问vertex
对于vertex的每个邻接节点neighbor
如果neighbor未被访问
标记neighbor为已访问
将neighbor加入queue
from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
visited.add(start)
while queue:
vertex = queue.popleft()
print(vertex, end=' ')
for neighbor in graph[vertex]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return visited
# 带路径记录的BFS实现
def bfs_with_path(graph, start, target):
visited = set()
queue = deque([(start, [start])]) # (节点, 路径)
visited.add(start)
while queue:
vertex, path = queue.popleft()
if vertex == target:
return path
for neighbor in graph[vertex]:
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, path + [neighbor]))
return None # 未找到路径import java.util.*;
public static void bfs(Map<Integer, List<Integer>> graph, int start) {
Set<Integer> visited = new HashSet<>();
Queue<Integer> queue = new LinkedList<>();
visited.add(start);
queue.offer(start);
while (!queue.isEmpty()) {
int vertex = queue.poll();
System.out.print(vertex + " ");
for (int neighbor : graph.getOrDefault(vertex, new ArrayList<>())) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
queue.offer(neighbor);
}
}
}
}
// 带路径记录的BFS实现
public static List<Integer> bfsWithPath(Map<Integer, List<Integer>> graph, int start, int target) {
Set<Integer> visited = new HashSet<>();
Queue<Pair> queue = new LinkedList<>(); // Pair包含节点和路径
visited.add(start);
queue.offer(new Pair(start, new ArrayList<>(Arrays.asList(start))));
while (!queue.isEmpty()) {
Pair current = queue.poll();
int vertex = current.vertex;
List<Integer> path = current.path;
if (vertex == target) {
return path;
}
for (int neighbor : graph.getOrDefault(vertex, new ArrayList<>())) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
List<Integer> newPath = new ArrayList<>(path);
newPath.add(neighbor);
queue.offer(new Pair(neighbor, newPath));
}
}
}
return null; // 未找到路径
}
// 辅助类
static class Pair {
int vertex;
List<Integer> path;
Pair(int vertex, List<Integer> path) {
this.vertex = vertex;
this.path = path;
}
}- 邻接表表示:O(V + E),其中V是顶点数,E是边数
- 邻接矩阵表示:O(V²)
- O(V) - 队列和visited集合的空间
在邻接表表示中,每个顶点和每条边都只会被访问常数次,队列中最多同时存在V个节点,因此时间和空间复杂度分别为O(V + E)和O(V)。
图的邻接表表示:
0: [1, 2]
1: [0, 3, 4]
2: [0, 5]
3: [1]
4: [1]
5: [2]
从节点0开始BFS遍历,访问顺序:0 -> 1 -> 2 -> 3 -> 4 -> 5
- 在加权图中寻找最短路径(需使用Dijkstra算法)
- 在社交网络中寻找两人之间的最短关系链
- 在游戏地图中寻找最短移动路径
- 空图
- 只有一个节点的图
- 不连通的图
- 有向图和无向图
可以通过动画演示BFS如何按层级扩展,以及队列如何管理待访问的节点。
- 可以找到从起始节点到其他节点的最短路径(无权图)
- 不会陷入很深的路径,避免栈溢出问题
- 实现相对简单
- 对于宽度优先的问题非常有效
- 空间复杂度较高,需要存储队列中的节点
- 对于深度较大的图,可能需要大量内存
- 对于只需要判断连通性的问题,可能不如DFS高效
相比于深度优先搜索(DFS),BFS能保证找到最短路径,但需要更多内存。
- 在无权图中寻找最短路径
- 社交网络中寻找两人之间的最短关系链
- 网页爬虫按层级爬取网页
- 广播网络中的消息传播
- 游戏中的寻路算法
- 图论算法
- 网络分析
- 社交网络分析
- 游戏开发
- 人工智能中的路径规划
- 分析BFS和DFS在不同图结构下的性能差异。
- 证明BFS能找到无权图中的最短路径。
- 实现BFS算法,处理各种边界条件。
- 使用BFS解决迷宫最短路径问题。
- 实现双向BFS以提高搜索效率。
设计一个社交网络分析工具,使用BFS算法分析用户之间的最短关系链。
- 图遍历算法的优化研究
- 在并行计算中的应用
- 《算法导论》中的图算法章节
- 《图论算法》相关书籍
- Dijkstra算法和A*算法相关资料
- 深度优先搜索(DFS)
- Dijkstra算法
- A*搜索算法
- 双向BFS