基本圖算法
一、圖的表示
對於圖G=(V,E),可以用兩種表示方法表示,一種將圖表示爲鄰接鏈表,另一種將圖表示爲鄰接矩陣。這兩種方法都既可以表示無向圖,又可以表示有向圖。
1. 鄰接鏈表
鄰接鏈表適用於稀疏圖(邊的條數
2. 鄰接矩陣
鄰接矩陣對圖G中的節點任意編號1,2,…,|V|,在編號後,用一個
使用鄰接矩陣表示一個圖,無論圖中邊的數量爲多少,其所需存儲空間均爲
3. 兩種表示方法的比較
鄰接矩陣表示比較簡單,所以在圖規模比較小的時候,可能更傾向於使用鄰接矩陣表示,而且對於無向圖來說,鄰接矩陣的一個優勢是每個記錄項只需要一位空間。
二、廣度優先搜索(BFS)
通常用於尋找特定源節點出發的最短路徑距離,所以圖通常爲連通圖。
廣度優先搜索是最簡單的圖算法之一,是許多圖算法模型的原型(Prim/Dijkstra等)。給定圖G=(V,E)和一個可以識別的源節點s,廣度優先搜索對圖G中的邊進行系統性的探索來發現可以從源節點s到達的所有節點。該算法能夠計算從源節點s到每個可到達節點的距離(最少的邊數),同時生成一棵“廣度優先搜索樹”。該樹以源節點s爲根節點,包含所有可以從s到達的節點。對於每個從源節點s可以到達的節點v,在廣度優先搜索樹裏從節點s到節點v的簡單路徑所對應的就是圖G中從節點s到節點v的“最短路徑”,即包含最少邊數的路徑。該算法對有向圖和無向圖同樣適用。
在執行廣度優先搜索的過程中將構造出一棵廣度優先樹。一開始該樹只有根節點,即源節點s。在掃描已發現節點u的鄰接鏈表時,每當發現一個未被發現的節點v,就將節點v和邊(u,v)同時加入該樹。以下爲算法導論中的BFS僞代碼,代碼中爲每個節點設置一個color屬性,白色節點爲未被發現節點,黑色節點和灰色節點均爲發現節點,區別在於黑色節點的所有鄰居節點都已經被發現,而灰色節點存在部分白色鄰居節點。
BFS(G,s)
// 初始化圖中除源節點s外的所有節點屬性
for each vertex u in G.V-{s}
u.color = WHITE // 未被發現
u.d = INF // 與源節點的距離爲無限大
u.pi = NIL // 前驅節點/父節點爲空
// 初始源節點s屬性
s.color = GRAY
s.d = 0
s.pi = NIL
Q = empty set // 初始化灰色節點集
ENQUEUE(Q, s)
while Q is NOT an empty set
u = DEQUEUE(Q)
for each v in G.Adj[u]
if v.color == WHILE
v.color = GRAY
v.d = u.d+1
v.pi = u
ENQUEUE(Q, v)
u.color = BLACK
算法複雜度分析:
每個節點的入隊操作和出隊操作最多均爲1次,入隊和出隊的時間均爲O(1),因此對隊列操作的總時間爲O(V)。因爲算法只在一個節點出隊時纔對該節點的鄰接鏈表進行掃描,所以每個鄰接鏈表最多隻掃描一次。由於所有鄰接鏈表的長度之和爲
三、深度優先搜索(DFS)
通常作爲另一個算法中的子程序,所以也常常用於不是連通圖的圖中。
深度優先搜索總是探索最近發現節點的子節點,知道探索到不存在子節點的節點v,則“回溯”到v的父節點,該過程一直持續到從源節點可以到達的所有節點都被發現爲止。若還存在未發現節點,則從未發現節點任選一個作爲新的源節點,重複同樣過程,直到所有節點都被發現。
類似廣度優先搜索算法,深度優先搜索在算法導論中同樣使用顏色屬性來指明節點狀態,初始爲白色,節點被發現爲灰色,節點的鄰接鏈表被掃描完成爲黑色。同時,深搜中每個節點有兩個時間戳:第一個時間戳v.d記錄節點v第一次被發現的時間(塗上灰色的時候);第二個時間戳v.f記錄搜索完成對v的鄰接鏈表掃描時間(塗上黑色的時候)。時間戳提供了圖結構的重要信息,通常能夠幫助推斷深度優先搜索算法的行爲。以下僞代碼給出基本的深度優先算法。
DFS(G)
for each vertex u in G.V
u.color = WHITE
u.pi = NIL
time = 0 // 全局變量,用於計算時間戳
for each vertex u in G.V
if u.color == WHITE
DFS-VISIT(G, u)
DFS-VISIT(G, u)
time = time+1 //白色節點u剛剛被發現
u.d = time
u.color = GRAY
for each v in G.Adj[u] // 探索邊(u,v)
if v.color = WHITE
v.pi = u
DFS-VISIT(G, v)
u.color = BLACK
time = time+1
u.f = time
算法複雜度分析:
對於DFS(G)函數,排除對DFS-VISIT(G,u)的調用,其所需時間爲
深搜中,節點的發現時間和完成時間具有括號化結構(parenthesis structure),則發現時間和完成時間的歷史記載形成規整的表達式,即所有括號都是正確的嵌套在一起,通過節點的兩個時間戳,可以確定兩個節點之間的關係(後代關係)。
四、強連通分量
強連通分量:對於有向圖G=(V,E),強連通分量是一個最大節點集合
強連通分量是深度優先搜索的一個經典應用,許多針對有向圖的算法都以此種分解操作開始。
尋找強連通分量需要對圖G=(V,E)進行轉置得到
STRONGLY-CONNECTED-COMPONENTS(G)
call DFS(G) t compute finishing time u.f for each vertex u
compute G^T
call DFS(G^T), but in the main loop of DFS, consider the vertices in order of decreasing u.f (as computed above)
output the vertices of each tree in the depth-first forest formed as a separate strongly connected component
該算法能夠正確工作的關鍵在於:在轉置圖