最小生成樹之克魯斯卡爾(kruskal)算法


 Kruskal算法

前面講了最小生成樹的Prim算法的實現思路是,通過頂點的擴展不斷地尋找最小權重的生成樹,而Kruskal算法是查找最小權值的邊,然后逐漸把連通分量變為一個聯結全部頂點的最小生成樹。

不同於 Prim算法 ,這次用邊集數組結構來實現 Kruskal算法 

結構很簡單,包括權值,邊的弧起點和終點的下標

將前面Prim例子中的圖轉化為邊集數組,並且按照權值升序排列儲存為 edges[] 這樣一個數組,那么這樣做的意義就在於后面按照權值的順序來安排邊,代碼如下:

 1 void MiniSpanTree_Kruskal(MGraph G)
 2 {
 3     int i,n,m;
 4     Edge edges[MAXVEX];
 5     int parent[MAXVEX];
 6     //這里省略構造edges數組時的排序步驟代碼
 7     for(i = 0;i < G.numVertexes;i++)
 8     {
 9         parent[i] = 0;
10     }
11     for(i = 0;i < G.numEdges;i++)
12     {
13         n = Find(parent,edges[i].begin);
14         m = Find(parent,edgws[i].end);
15         if(n != m)
16         {
17             parent[n] = m;
18             //將這一條邊的結尾頂點下標存在數組起點下標的位置
19             printf("(%d %d) %d",edges[i].begin,edges[i].end,edges[i].weight);
20         }
21     }
22 }
23 
24 int Find(int *parent,int f)
25 {
26     while(parent[f] > 0)
27         f = parent[f];
28     return f;
29 }

我們來讀一哈這個代碼:

3~10行定義邊集數組以及初始化 parent 數組,后面詳細講解這個數組的用處

代碼結構較為簡單,故講解11~22行循環,夾雜 Find 函數實現

第一次循環: n = 4 ,m = 7, parent = {0,0,0,0,7,0,0,0,0,0,0,0,0,0,0} ,然后打印邊的起點終點和權值,此時 parent 數組以數字下標位置和內容表示(v4 v7)這條邊已經加入豪華最小生成樹

第二次循環:n = 2 ,m = 8, parent = {0,0,8,0,7,0,0,0,0,0,0,0,0,0,0} ,然后打印邊的起點終點和權值,此時 parent 數組以數字下標位置和內容表示(v2 v8)這條邊已經加入豪華最小生成樹

 

 第三次循環:n = 0 ,m = 1, parent = {0,1,8,0,7,0,0,0,0,0,0,0,0,0,0} ,然后打印邊的起點終點和權值,此時 parent 數組以數字下標位置和內容表示(v0 v1)這條邊已經加入豪華最小生成樹

 第三、四、五、六次循環:因為循環中的判斷條件和之前一樣, 故第六次循環后parent = {1,5,8,7,7,8,0,0,6,0,0,0,0,0,0} ,然后不斷打印邊(v0,v5)(v1,v8)(v3,v7)(v1,v6)的起點終點和權值

當 i = 7 時,我們會發現對應的是 (v5 v6)這條邊,如果打印這條邊,則會生成閉環,就不符合我們最小生成樹的結構要求,那么我們來跑一下 11行的循環, 調用Find函數,會傳入參數 edges[7].begin = 5,此時 Find函數內部,parent[5] = 8,大於0, m = f = parent[8] = 6,而 edges[7].end = 6,傳入Find 得 n = 6,此時m = n,不打印結點信息,(否則將形成閉環)

后面的 i = 8、 i = 9均為閉環所以均不打印

生成樹為

Kruskal算法總結:

假設 N= (V,{E})是連通網,則令最小生成樹的初始狀態為只有 n 個頂點而無邊的非連通圖 T={V,{}},圖中每個頂點自成一個連通分量。在 E 中選擇代價最小的邊,若該邊依附的頂點落在 T 中不同的連通分量上,則將此邊加入到 T 中,否則舍去此邊而選擇下一條代價最小的邊。依次類推,直至 T 中所有頂點都在同一連通分量上為止。
此算法的 Find 函數由邊數 e 決定,時間復雜度為 O(loge)而外面有一個 for 循環 e 次。 所以克魯斯卡爾算法的時間復雜度為 O(eloge).
對比兩個算法,Kruskal算法主要是針對邊來展開,邊數少時效率會非常高,所以對於稀疏圖有很大的優勢,而Prim算法對於稠密圖,即邊數非常多的情況會更好一些。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM