資料結構——圖(8)——最小生成樹(MST)
阿新 • • 發佈:2018-11-10
問題的提出
如下圖,假設這裡有一系列的房屋,問如何鋪設電線,可以使得連線所有房屋的電線的總成本最低?這是20世紀20年代早期研究最小生長樹的最初動機。 (捷克數學家OtakarBorůvka完成的工作)。
最短路徑樹與最小生成樹(MST)
上次,我們看到了Dijkstra演算法如何用於在圖中找到最短路徑樹。請注意,最短路徑樹可能不是MST,反之亦然。為什麼這麼說呢?
最小生成樹(或MST)是總成本最低的生成樹。
最短路徑樹(Shortest Path Tree, SPT),是一種使用最短路徑演算法生成的資料結構樹。
一個是成本最低,一個是路徑最短。
假設有一個圖如下:
那麼對於星號節點而言,它的最短路徑樹(左圖),和最小生成樹(右圖)分別如下圖所示。
MST演算法的發展
- Borůvka提出的原始MST演算法(1926)現在稱為Borůvka演算法。
- 後來,捷克數學家VojtěchJarník(1930)發明了一種現在稱為Prim演算法的演算法。
- 之後,美國數學家Joseph Kruskal(1956)開發了現在稱為Kruskal演算法的演算法,這就是我們今天要呈現的演算法。
Kruskal’s Algorithm
這個演算法聽起來似乎很簡單:從圖表中刪除所有邊。 反覆找到造成迴圈的且花費最小的邊並將其添加回來。 最終的結果就是整個圖的MST
用虛擬碼可以表示為這樣:
function kruskal(graph): //從圖中移除所有邊 Remove all edges from the graph. //將所有邊放入優先順序佇列(基於它們自身的權重) Place all edges into a priority queue,based on their weight //當優先順序佇列不為空時 While the priority queue is not empty: //將邊從優先順序佇列中取出 Dequeue an edge e from the priority queue. //如果這條邊新增上圖中不會構成迴圈,則將此邊新增到圖中 If e's endpoints doesn’t create a cycle ,add that edge into the graph. //否則,跳過該邊 Otherwise, skip the edge.
來看下面的一幅帶權圖,我們試著用這種方法來找到該圖的最小生成樹。
- 首先我們先將圖中的所有邊刪除,用虛線表示刪除的邊
此時,優先順序佇列的情況是這樣的:
pq = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18}
- 根據演算法,我們從優先順序佇列中取出隊頭 a:2.將它新增到圖中,發現不構成環狀,於是新增到圖中(實線部分)
- 接著我們繼續將優先順序佇列中的其他元素新增到圖中,接下來是b:2,結果符合要求,於是加到佇列中:
- 重複此次步驟。
- 當新增邊到e:5時,我們發現此時構成了一個環狀(紅色部分),因此這條邊不能加在圖中,應該跳過這個邊,繼續新增接下來的邊(如圖):
- 當優先順序中的佇列為空時,表明我們已經將所有的邊都遍歷了一遍,此時生成的結果就是我們要找的MTS,如圖:
- 結果
Kruskal’s 演算法會按如下順序輸出所需的 MST:
{a, b, c, d, f, h, i, k, p}
而 MST’s 總花費(權重)為:
1+2+3+4+6+8+9+11+16 = 60