算法复习——图算法篇之广度优先搜索
以下内容主要参考中国大学MOOC《算法设计与分析》,墙裂推荐希望入门算法的童鞋学习!
1. 问题背景
图的搜索
- 数组结构
- 查询最大值:简单循环搜索所有元素,记录最大值
- 图结构
- 查询相邻顶点:简单循环搜索各顶点关联的边
- 查询可达顶点:简单循环搜索,不能找到全部可达顶点!
因此,我们需要按照特定的次序搜索顶点,于是引出了两种搜索策略:广度优先搜索和深度优先搜索。深度优先搜索可参考算法复习——图算法篇之深度优先搜索。
2. 算法思想
- 队列
- 先来先服务:队尾加入,队首离开
- 加入队列, Q . E n q u e u e ( ) Q.Enqueue() Q.Enqueue()
- 离开队列, Q . D e q u e u e ( ) Q.Dequeue() Q.Dequeue()
- 先来先服务:队尾加入,队首离开
- 核心思想
- 处理某顶点时,一次性发现其所有相邻顶点,未处理顶点加入等待队列
- 辅助数组
-
c
o
l
o
r
color
color表示顶点状态
- W h i t e White White:白色顶点 u u u尚未被发现,发现后直接入队
- B l a c k Black Black:黑色顶点 u u u已被处理,无需再次入队
- G r a y Gray Gray:灰色顶点 u u u已加入队列,无需再次入队
- p r e d pred pred:顶点 u u u由 p r e d [ u ] pred[u] pred[u]发现
- d i s t dist dist:顶点 u u u距离源点 s s s的距离
-
c
o
l
o
r
color
color表示顶点状态
3. 广度优先树
- 辅助数组 p r e d [ ] pred[] pred[]储存了一棵树,广度优先树 T = < V T , E T > T=<V_T,E_T> T=<VT,ET>
- V T V_T VT为源点 s s s可达的顶点结合, E T = { ( p r e d [ u ] , u ) : u ∈ V T } E_T=\{(pred[u], u):u \in V_T\} ET={(pred[u],u):u∈VT}
4. 伪代码
BFS(G, s)
输入:图 G G G,源点 s s s
输出:前驱数组 p r e d [ ] pred[] pred[],距离数组 d i s t [ ] dist[] dist[]
新建一维数组color[1..|V|], pred[1..|V|], dist[1..|V|]
新建空队列Q
// 初始化
for u ∈ V do
color[u] ← WHITE
pred[u] ← NULL
dist[u] ← ∞
end
color[s] ← GRAY
dist[s] ← 0
Q.Enqueue(s)
// 广度优先搜索
while 等待队列Q非空 do
u ← Q.Dequeue()
for v ∈ G.Adj[u] do
if color[v] = WHITE then
color[v] ← GRAY
dist[v] ← dist[u] + 1
pred[v] ← u
Q.Enqueue(v)
end
end
color[u] ← BLACK
end
对于每个顶点 u u u,搜索相邻顶点消耗时间 T u = O ( 1 + d e g ( u ) ) T_{u}=O(1+deg(u)) Tu=O(1+deg(u)),总运行时间 T ≤ ∑ u ∈ V T u = ∑ u ∈ V O ( 1 + d e g ( u ) ) = ∑ u ∈ V O ( 1 ) + ∑ u ∈ V O ( d e g ( u ) ) = O ( ∣ V ∣ + ∣ E ∣ ) T \leq \sum_{u \in V}T_u=\sum_{u \in V}O(1+deg(u))=\sum_{u \in V}O(1)+\sum_{u \in V}O(deg(u))=O(|V|+|E|) T≤∑u∈VTu=∑u∈VO(1+deg(u))=∑u∈VO(1)+∑u∈VO(deg(u))=O(∣V∣+∣E∣)。
所以,广度优先搜索的时间复杂度为 O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(∣V∣+∣E∣),简记为 O ( V + E ) O(V+E) O(V+E)。
5. 相关应用
5.1 最短路径
d i s t [ ] dist[] dist[]和 p r e d [ ] pred[] pred[]数组记录了无权图从源点出发到各个点的最短路径。