第22章 基本的图算法
22.1 图的表示
对于图G=(V,E),可以用两标准表示方法表示,一种表示法将图作为邻接链表的组合,另一种表示法则将图作为邻接矩阵来看待,本书采用邻接链表。 邻接链表表示由一个包含 |V| 条链表的数组 Adj 所构成,每个结点有一条链表。对于每个结点 u∈V ,邻接链表 Adj[u] 包含所有与结点u之间有边相连的结点v。
22.2 广度优先搜索
每个结点u的颜色属性放在属性x.color中,将u的前驱结点存放在属性u.p中,若没有前驱则u.p=NIL。属性u.d记录的是广度优先搜索算法所计算出的从源结点s到结点u之间的距离。
BFS(G,s){
for u in G.V-{s}
u.color = white
u.d = \inf
u.p = NIL
s.color = gray
s.d = 0
s.p = NIL
Q = new QUEUE()
ENQUEUE(Q,s)
while !Q.isEmpty {
u = DEQUEUE(Q)
for v in G.Adj[u]
if v.color == white
v.color = gray
v.d ++
v.p = u
EVQUEUE(Q,v)
u.color = black
}
}
22.3 深度优先搜索
1、深度优先搜索算法还在每个结点盖上一个时间戳。每个结点v有两个时间戳:第一个时间戳v.d记录结点v第一次被发现的时间(涂上灰色的时间),第二个时间戳v.f记录的是搜索完成对v的邻接链表扫描的时间(涂上黑色的时间)。time为全局变量。
DFS(G){
for u in G.V
u.color = white
u.p = NIL
time = 0
for u in G.V
if u == white
DFS-VISIt(G,u)
}
DFS-VISIT(G,u){
time ++
u.d = time
u.color = gray
for v in G.Adj[u]
if v.color == white
v.p = u
DFS-VISIT(G,v)
u.color = black
time ++
u.f = time
}
深度优先搜索算法的运算时间为 Θ(V+E) 。
2、深度优先搜索的另一个重要的性质是,结点的发现时间和完成时间具有所谓的括号化结构。
定理(括号化定理):在对有向或无向图G=(V,E)进行的任意深度优先搜索中,对于任意两个结点u和v来说,下面三种情况只有一种成立:
- 区间[u.d,u.f]和区间[v.d,v.f]完全分离,在深度优先森林中,结点u不是结点v的后代,结点v也不是结点u的后代。
- 区间[u.d,u.f]完全包含在区间[v.d,v.f]内,在深度优先树中,结点u是结点v的后代。
- 区间[v.d,v.f]完全包含在区间[u.d,u.f]内,在深度优先树中,结点v是结点u的后代。
22.4 拓扑排序
拓扑排序是G中所有结点的一种线性次序,该次序满足如下条件:如果图G包含边(u,v),则结点u在拓扑排序中处于结点v的前面。
拓扑排序主要思想:
- DFS(G)计算每个结点v的v.f
- 按v.f降序排列