目錄
- 1.圖的表示
- 2.廣度優先搜索
- 3.深度優先搜索——本質等同于回溯
- 4.拓撲排序
- 5.強連通分量
1.圖的表示
- 鄰接鏈表是表示稀疏圖(|E| << |V|2)通常的選擇
1)由一個包含|V|條鏈表的所組成,每個結點一條鏈表。
2)對于每個結點u∈V,鄰接鏈表Adj[u]包含所有與結點u之間有邊相連的結點v
3)鄰接鏈表表示法的存儲空間需求是Θ(V+E) - 鄰接矩陣是表示稠密圖(|E| ≈ |V|2)的通常選擇
如果需要快速判斷任意兩個結點之間是否有邊連接,可能也需要鄰接矩陣表示法。
1)鄰接矩陣是由一個|V| x |V|的矩陣A = (aij)表示的
2.廣度優先搜索
- 圖的搜索:系統化地跟隨圖中的邊來訪問圖中的每個結點。
圖搜索算法可以用來發現圖的結構。許多圖算法在一開始都會先通過搜索來獲得圖的結構,其他的一些圖算法則是對基本的搜索加以優化。
圖的搜索技巧是整個圖算法領域的核心。 - Prim最小生成樹算法和Dijkstra單源最短路徑算法都使用了類似廣度優先搜索的思想。
2.1 廣度優先搜索
廣度優先搜索的特點:算法始終是沿著 已發現結點和未發現結點邊界 的廣度方向向外擴展。
即算法需要在發現所有距離源節點s為k(k條邊)的所有結點之后,才會發現距離源節點s為k+1的其他節點。結點分為三類:
白色:開始時都涂為白色
黑色:所有與黑色結點鄰接的結點都已被發現
灰色:其鄰接結點中可能存在未被發現的白色結點。(是已知和未知兩個集合之間的邊界。)執行廣度優先搜索的過程中,將構造出一棵以s為根的廣度優先樹。
-
隊列Q中管理灰色結點集
-
BFS計算出的廣度優先樹可以因鄰接鏈表中的次序不同而不同,但是結點u的u.d值與次序無關。
與距離為d相鄰接的白色邊,全為d+1,廣度優先樹的搜索次序會將d+1的邊連接到不同的d邊上,但不會改變其距離。
BFS的運行時間:
1)每個結點入隊和出對最多一次,總時間為O(V)
2)對每個結點進行鄰接鏈表掃描(最多一次),因此掃描鄰接鏈表的時間為O(E)
總時間為O(V + E)
2.2 最短路徑
- 定義從源節點s到結點v的最短路徑距離δ(s, v)為從結點s到結點v之間所有路徑里面最少的邊數。
從結點s到結點v的長度為δ(s, v)的路徑為s到v的最短路徑。
- 定理22.3其實本質上是指:當刪除一個距離為d的結點時,才會將結點相鄰的結點加入進來,此時距離為d+1。所以隊列中頭尾最大差1.
- 22.5的理解:
1)關鍵點:v是第一個不滿足要求的結點,u是s到v的最短路徑上v的前驅
2)v分別是三種顏色時,此時假設結點u還在隊列中
2.3 廣度優先樹
- 對于圖G=(V, E)和源節點s,定義圖G的前驅子圖為Gπ = (Vπ, Eπ),其中:
Vπ={v∈V: v.π ≠ NIL} ∪ {s}
Eπ = {(v.π, v): v∈Vπ - {s}} - 如果Vπ由源節點s可以到達的結點組成,并且對于所有的v∈Vπ,子圖Gπ包含一條從源節點s到結點v的唯一簡單路徑,且該路徑也是圖G里面從源節點s到結點v之間的一條最短路徑,則前驅子圖Gπ是一棵廣度優先樹。
|Eπ| = |Vπ| - 1
3.深度優先搜索——本質等同于回溯
3.1 深度優先搜索
- (回溯)只要可能,就在圖中盡量“深入”。
深度優先搜索總是對最近才發現的結點v的出發邊進行搜索,直到該節點的所有出發邊都被發現為止。一旦結點v的所有出發邊都被發現,搜索則回溯到v的前驅結點,來搜索該前驅結點的其他出發邊。
該過程一直持續到從源節點可以達到的所有結點都被發現為止。 -
前驅子圖:Gπ = (V, Eπ),其中:
Eπ = {(v.π, v): v∈V且v.π ≠ NIL }
深度優先搜索的前驅子圖形成一個由多棵深度優先樹構成的深度優先森林。森林Eπ中的邊稱為樹邊。
深度優先搜索的前驅子圖可能由多棵樹組成,因為搜索可能從多個源節點重復進行。 -
結點分為三類:
白色:開始時都涂為白色
黑色:其鄰接鏈表被掃描完成后變為黑色。
灰色:其鄰接結點中可能存在未被發現的白色結點。(是已知和未知兩個集合之間的邊界。)
該方法可以保證每個結點僅在一棵深度優先樹中出現,因此,所有的深度優先樹是不相交的。 - 每個結點蓋上時間戳:
1)v.d:記錄結點v第一次被發現的時間(涂上灰色的時候)
2)v.d:對v的鏈接鏈表完成搜索掃描的時間(涂上黑色的時間)
結點v在v.d之前是白色,在v.d和v.f之間為灰色,在v.f之后是黑色。
- 運行時間:
DFS-VISIT被調用的次數剛好為一次,只有當u為白色的時候,才調用。Θ(V)。
遍歷鄰接遍歷總共執行的是Θ(E)。
總共Θ(V + E)
3.2 深度優先搜索的性質
- 深度優先搜索具有括號化結構
3.3 邊的分類
在圖G上運行深度優先搜索算法所生成的深度優先森林Gπ,定義四種邊的類型:
1)樹邊
為深度優先森林Gπ中的邊。如果結點v是因算法對邊(u, v)的探索而首先被發現,則(u, v)是一條樹邊
2)后向邊
后向邊(u,v)是將結點u連接到其在深度優先樹中(一個)祖先結點v的邊。由于有向圖可以有自循環,自循環也被認為是后向邊。
3)前向邊
是將結點u連接到其在深度優先樹中一個后代結點v的邊(u, v)
4)橫向邊
指其他所有的邊。這些邊可以連接同一棵深度優先樹中的結點,只要其中一個結點不是另一個結點的祖先,也可以連接不同深度優先樹中的兩個結點。當第一次探索邊(u, v)時
1)結點v為白色表明該條邊(u, v)是一條樹邊
2)結點v為灰色表明該條邊(u, v)是一條后向邊:v.d < u.d < u.f < v.f
3)結點v為黑色表明該條邊(u, v)是一條前向邊或橫向邊 v.f < u.f:有兩種情況-
對邊進行分類時,為了消除無向圖的模糊性:
將邊(u, v)花費為分類列表中第一種適合該邊的類型;
可以根據搜索算法時是先搜索到邊(u, v)還是(v, u)來進行分類
該定理的關鍵點:第一次探索邊(u ,v),分為兩種情況。
一種是u->v方向,這時是樹邊
第二種是v->u方向,這時是后向邊
4.拓撲排序
- 使用深度優先搜索對有向無環圖進行拓撲排序
- (拓撲排序)對于一個有向無環圖G = (V, E)來說,其拓撲排序是G中所有結點的一種線性次序,該次序滿足如下條件:
如果圖G包含邊(u ,v),則結點u在拓撲排序中出于結點v的前面(如果G含有回路,則不可能排出一個線性次序)。
- 拓撲排序的本質是:按照其完成時間的逆序被排成從左至右的一條水平線。所有的有向邊都是從左指向右。
- 運行時間:深度優先搜索的運行時間為Θ(V + E),將結點插入到鏈表最前端所需的時間為O(1),一共只有|V|結點需要插入,總共需要Θ(V + E)時間
- 定理22.12能夠成立的原因是:因為沒有后向邊
5.強連通分量
5.1 強連通算法
(強連通)如果一個有向圖中任意兩個頂點互相可達,則該有向圖是強連通的。有向圖的強連通分量是“相互可達”關系下頂點的等價類。
有向圖G = (V, E)的強連通分量是一個最大結點集合 C包含于V,對于該集合中的任一對結點u和v來說,路徑 u ->...-> v和v ->...-> u同時存在,也就是u和v可以互相可達。(轉置GT)尋找連通分量的算法需要用到圖G=(V, E)的轉置,將其定義為GT = (V, ET)
ET = {(u, v): (v, u) ∈ E}
ET是由圖G中的邊進行反向而獲得的。
圖G和GT的強連通分量是完全相同的(算法)在Θ(V + E)時間使用使用兩次深度優先搜索來計算有向圖G = (V, E)的強連通分量。這兩次搜索一次運行在G上,一次運行在GT上。
-
第二次實際上是以拓撲排序的次序來訪問分量圖中的結點。
- 算法的思想來自于圖GSCC = (VSCC, ESCC)的一個關鍵性質,這個關鍵性質定義如下:
假定圖G有強連通分量C1, C2, ..., Ck。結點集VSCC為{v1, v2, ..., vk},對于圖G的每個強連通分量Ci來說,該集合包含代表該分量的結點vi。如果對于某個x∈Ci和y∈Cj,圖G包含一條有向邊(x, y),則邊(vi, vj)∈ESCC。
另一個角度來看,通過收縮所有相鄰結點都在同一個強連通分量中的邊,剩下的圖就是GSCC。
5.2 分量圖是有向無環圖
5.3 算法正確性
-
d(U)和f(U)分別是集合U中所有結點里最早的發現時間和最晚的完成時間。
- 算法的關鍵:對GT的深度優先搜索訪問任意一個強連通分量時,從該連通分量發出的所有邊只能是通向已經訪問過的強連通分量。
- 從另一個角度來看第二次深度優先搜索的過程:
考慮GT的分量圖(GT)SCC。如果將第二次深度優先搜索所訪問的每個強連通分量映射到(GT)SCC的一個結點上,則第二次深度優先搜索將以拓撲排序的逆序來訪問(GT)SCC中的結點。
如果將(GT)SCC中的邊翻轉過來,將獲得圖((GT)SCC)T。
因為((GT)SCC)T = GSCC,因此第二次深度優先搜索是以拓撲排序次序訪問GSCC中的結點的。
上述等式的含義:轉置圖的分量圖的轉置與圖G的分量圖相同。