Kruskal 最小生成樹演算法

Dennis Gao的部落格發表於2015-02-01

對於一個給定的連通的無向圖 G = (V, E),希望找到一個無迴路的子集 T,T 是 E 的子集,它連線了所有的頂點,且其權值之和為最小。

因為 T 無迴路且連線所有的頂點,所以它必然是一棵樹,稱為生成樹(Spanning Tree),因為它生成了圖 G。顯然,由於樹 T 連線了所有的頂點,所以樹 T 有 V – 1 條邊。一張圖 G 可以有很多棵生成樹,而把確定權值最小的樹 T 的問題稱為最小生成樹問題(Minimum Spanning Tree)。術語 “最小生成樹” 實際上是 “最小權值生成樹” 的縮寫。

Kruskal 演算法提供一種在 O(ElogV) 執行時間確定最小生成樹的方案。Kruskal 演算法基於貪心演算法(Greedy Algorithm)的思想進行設計,其選擇的貪心策略就是,每次都選擇權重最小的但未形成環路的邊加入到生成樹中。其演算法結構如下:

  1. 將所有的邊按照權重非遞減排序;
  2. 選擇最小權重的邊,判斷是否其在當前的生成樹中形成了一個環路。如果環路沒有形成,則將該邊加入樹中,否則放棄。
  3. 重複步驟 2,直到有 V – 1 條邊在生成樹中。

上述步驟 2 中使用了 Union-Find 演算法來判斷是否存在環路。

例如,下面是一個無向連通圖 G。

圖 G 中包含 9 個頂點和 14 條邊,所以期待的最小生成樹應包含 (9 – 1) = 8 條邊。

首先對所有的邊按照權重的非遞減順序排序:

然後從排序後的列表中選擇權重最小的邊。

1. 選擇邊 {7, 6},無環路形成,包含在生成樹中。

2. 選擇邊 {8, 2},無環路形成,包含在生成樹中。

3. 選擇邊 {6, 5},無環路形成,包含在生成樹中。

4. 選擇邊 {0, 1},無環路形成,包含在生成樹中。

5. 選擇邊 {2, 5},無環路形成,包含在生成樹中。

6. 選擇邊 {8, 6},有環路形成,放棄。

7. 選擇邊 {2, 3},無環路形成,包含在生成樹中。

8. 選擇邊 {7, 8},有環路形成,放棄。

9. 選擇邊 {0, 7},無環路形成,包含在生成樹中。

10. 選擇邊 {1, 2},有環路形成,放棄。

11. 選擇邊 {3, 4},無環路形成,包含在生成樹中。

12. 由於當前生成樹中已經包含 V – 1 條邊,演算法結束。

C# 實現的 Kruskal 演算法如下。

輸出結果如下:

參考資料

相關文章