1. 程式人生 > >資料結構——圖(8)——最小生成樹(MST)

資料結構——圖(8)——最小生成樹(MST)

問題的提出

如下圖,假設這裡有一系列的房屋,問如何鋪設電線,可以使得連線所有房屋的電線的總成本最低?這是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.

來看下面的一幅帶權圖,我們試著用這種方法來找到該圖的最小生成樹。

  1. 首先我們先將圖中的所有邊刪除,用虛線表示刪除的邊

在這裡插入圖片描述
此時,優先順序佇列的情況是這樣的:
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}

  1. 根據演算法,我們從優先順序佇列中取出隊頭 a:2.將它新增到圖中,發現不構成環狀,於是新增到圖中(實線部分)在這裡插入圖片描述
  2. 接著我們繼續將優先順序佇列中的其他元素新增到圖中,接下來是b:2,結果符合要求,於是加到佇列中:
    在這裡插入圖片描述

    在這裡插入圖片描述
  3. 重複此次步驟。
  4. 當新增邊到e:5時,我們發現此時構成了一個環狀(紅色部分),因此這條邊不能加在圖中,應該跳過這個邊,繼續新增接下來的邊(如圖):
    在這裡插入圖片描述
  5. 當優先順序中的佇列為空時,表明我們已經將所有的邊都遍歷了一遍,此時生成的結果就是我們要找的MTS,如圖:
    在這裡插入圖片描述
  6. 結果
    Kruskal’s 演算法會按如下順序輸出所需的 MST:
    {a, b, c, d, f, h, i, k, p}
    而 MST’s 總花費(權重)為:
    1+2+3+4+6+8+9+11+16 = 60