数据结构(5) -- 图
5.4 圖的應用
圖的應用主要包括:最小生成樹、最短路徑、拓撲排序和關鍵路徑
5.4.1 最小生成樹(MST)
連通圖的生成樹:圖的極小連通子圖,包含圖中所有頂點,只含盡可能少的邊。若砍去最小生成樹的一條邊,使生成樹變成非連通圖,加上一條邊,會形成一條回路。
最小生成樹:邊權值最小的那棵生成樹
最小生成樹不唯一,但權值唯一,且是最小的。
算法:prim算法/kruskal算法,都是基于貪心算法
prim算法:
假設N={V,E}是連通網,ET是N上最小生成樹邊的集合。算法從VT-{u0},ET={}開始,重復執行:在所有u∈VT,v∈V-VT的邊(u0,v0)∈E中找一條權值最小的邊,將此邊加入ET,將v0加入VT,知道VT=V為止。
該算法時間復雜度O(|v2|),不依賴E,適用于求解邊稠密的圖的最小生成樹
kruskal算法:
初始化:VT=V,ET=?,每個頂點構成一棵獨立的樹
循環:按G的邊權遞增順序依次從E-ET選一條邊,若加入邊后不構成回路,則加入ET,否則舍棄。
通常采用堆來存放邊的集合,每次選擇最小權值的邊只需要O(log|E|),可以采用并查集的數據結構表示T,構造T的復雜度為O(|E|log|E|)
適合邊稀疏,頂點較多的圖
5.4.2 最短路徑
帶權路徑長度最短的路徑稱最短路徑。求解最短路徑的算法通常依賴一性質:兩點之間的最短路徑也包含了路徑上其他頂點間的最短路徑。一般分單源最短路徑(某點到其他點的最短路徑)和每對頂點間的最短路徑。
問題:對任意給出的圖G(V,E)和起點s,終點t,如何求S到T的最短路徑。
解決最短路徑問題的常用算法有 Dijkstra算法、Bellman-Ford算法、SPFA算法和Floyd算法。
1. Dijkstra算法
思想:對圖G設定集合S,存放已經訪問過的集合。然后從V-S中選擇與起點s距離最短的頂點記為u,訪問并加入集合S。之后,令頂點u為中介點,優化起點s與所有從u出發能到達的頂點v之間的最短距離。執行n次,直到集合S包含所有頂點。
算法具體實現:
(1)集合S可以用一個bool數組vis[]表示,當vis[i]=true時表示頂點Vi已被訪問。
(2)令int型數組d[]表示起點s到達頂點Vi的最短距離,起始時除了起點s的d[s]=0,其余頂點都賦為一個很大的數。
Dijkstra也基于貪心策略,時間復雜度O(|V2|),若要求解每對頂點之間的最短距離,需要對每個頂點運行一次dijkstra算法,復雜度O(|V3|)
注:Dijkstra只能應對所有邊權都是非負數的情況,如果邊權出現負數,那么Dijkstra算法可能會出錯。
//偽代碼 Dijkstra(G,d[],s){初始化;for(循環n次){u = 使d[u]最小的還未被訪問的頂點的標號;記u被訪問;for(從u出發能到達的所有頂點v){if(v未被訪問&&以u為中介使s到頂點v的最短距離d[v]更優){優化d[v];}} }2. Bellman-Ford算法和SPFA算法
Bellman-Ford算法(BF算法)可解決單源最短路徑問題,但能處理有負邊權的情況。
現在考慮環,從某個頂底出發,經過若干不同的頂點之后可以回到該頂點的情況。根據環中邊的邊權之和的正負分零環、正環、負環。零環和正環不會影響最短路徑的求解;而如果有負環,且從源點可以到達,就會影響求解,但如果負環無法從源點出發到達,則最短路徑的求解不會受到影響。
思想:BF算法設置一個數組d,存放從源點到達各個頂點的最短距離。同時BF算法返回一個bool值:若存在從源點可到達的負環,返回false;否則返回true,此時數組d存放的值就是從源點到達各頂點的最短距離。
具體實現:
對圖中邊進行V-1輪操作,每輪都遍歷圖中所有的邊:對每條邊u->v,若以u為中介點能使d[v]更小,就更新。
for(i = 0; i < n-1; i++){for(each edge u—>v){if(d[u]+length[u->v] < d[v]){d[v] = d[u] + length[u->v];}} }此時,若無從源點可到達的負環,則數組d所有值都達到了最優。因此,只需再對所有邊進行一輪操作,判斷是否有某條邊u->v仍然可以更新,若有,則說明圖中有從源點可達的負環,返回false;否則,說明d數組已達到最優。
BF算法時間復雜度為O(VE)
?
雖然BF算法思路簡潔,但時間復雜度很高。BF算法每輪操作都操作所有的邊,顯然有很多無意義的操作。注意到,只有當某個頂點u的d[u]值改變時,從它出發的邊的鄰接點v的d[v]值才有可能改變。由此可以進行優化:建立一個隊列,每次取出隊首u,對從u出發的邊進行松弛。如果可松弛則進行覆蓋。如果v不在隊列,則加入隊列。這樣操作直到隊空(說明無從源點可達的負環),或某個頂點的入隊次數超過v-1,說明有可達負環。這樣優化后的算法叫做SPFA算法。它期望的時間復雜度是O(kE)
queue<int> Q; 源點s入隊; while(隊非空){取出隊首元素u;for(u的所有鄰接邊u->v){if(d[u]+dis<d[v]){d[v] = d[u]+dis;if(v不在Q){v入隊;if(v入隊次數大于n-1){說明有可達負環,return;}}}} }3. Floyd算法
解決全源最短路問題。時間復雜度O(n^3),限制頂點數n在200以內。
枚舉頂點k∈[1,n]以頂點k為中介點,枚舉所有頂點對i和j(i∈[1,n],j∈[1,n])如果 dis[i][k]+dis[k][j] < dis[i][j]成立賦值 dis[i][j] = dis[i][k]+dis[k][j]5.4.3 拓撲排序
有向無環圖:若一個有向圖中不存在環,稱DAG圖
AOV網:DAG表示一個工程,頂點表示活動,有向邊<vi, vj>表示活動vi必須先于vj進行。稱頂點表示活動的網絡,記為AOV網,拓撲排序復雜度O(|V|+|E|)
AOE網:在帶權有向圖中,以頂點表示事件,有向邊表示活動,邊上的權值表示完成該活動所需開銷。
最大路徑:源點到匯點的所有路徑中,具有最大路徑長度的路徑稱關鍵路徑,關鍵路徑上的活動稱關鍵活動。
總結
以上是生活随笔為你收集整理的数据结构(5) -- 图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构(3) -- 栈和队列
- 下一篇: 数据结构(6) -- 查找