摘要:求解圖的最小生成樹在工程管理、最優化規劃等領域有廣泛的應用,因此對最小生成樹算法的研究具有重要的意義。本文針對圖的最小生成樹算法,首先對幾種經典的最小生成樹算法進行了總結,最後針對無向連通網的最小生成樹問題,分別使用普利姆算法和克魯斯卡爾算法進行了詳細的算法原理分析與程序實現。
關鍵詞:無向連通網;最小生成樹算法;普利姆算法;克魯斯卡爾算法
The Minimum Spanning Tree Algorithm of undirected connected network
Abstract:The minimum spanning tree of graphs is widely used in engineering management, optimization planning and other areas, so it is very important to study the minimum spanning tree algorithm. In this paper, Several classical minimum spanning tree algorithms are summarized, At the same time, a detailed algorithm analysis and program realization are carried out for the minimum spanning tree problem of undirected connected network by using the Prim algorithm and the Kruskal algorithm.
Key words:Undirected connected network;MST;Prim algorithm;Kruskal algorithm
1 引 言
求解圖的最小生成樹(Minimum Spanning Tree,MST)屬於圖論的典型應用問題。其中,連通圖的最小生成樹在理論研究和工程設計上均有廣泛的研究和應用,因此最小生成問題從提出到理論描述,再到算法實現方式都取得了豐富的研究和應用成果。迄今爲止,國內外學者就最小生成樹問題,分別針對有向圖和無向圖提出了多種解決策略。其中,針對帶權值的有向圖,吳文虎等[1]提出了通過有向圈的收縮和展開求解最小生成樹的策略;馮俊文[2]等提出了基於表格表示的表上作業法;對於無向圖的最小生成樹算法,包含Prim算法、Kruskal算法、Dijkstra最小生成樹等經典的求解算法[3]。本文針對無向連通網的最小生成樹問題,首先針對經典的Prim算法通過從部分最小生成樹邊集合擴展的角度逐步從剩餘候選邊集中選取最小邊構造最小生成樹;針對Kruskal算法可能的環路問題,通過使用並查集[4-5]來對所選的邊進行連通分量的判斷,同時對所選邊集合進行路徑壓縮提高下一次查詢效率。最後給出了詳細的算法設計流程和實例驗證。
2 算法描述
最小生成樹問題在實際的工程管理、最優化規劃等方面有實際的應用價值,例如交通路網的規劃、旅行路線規劃、通信網絡設計、故障診斷[6-7]等。因此在基於圖論的應用問題中,通常需要對帶權值的無向連通圖求最小生成。在求無向連通網的最小生成樹時,需要預先構造一個帶權值的無向連通圖並用鄰接矩陣表示圖的存儲結構,無向連通網和鄰接矩陣表示分別如下所示(其中*表示距離爲無窮)。
在最小生成樹的求解算法中,Prim算法和kruskal算法使用最爲廣泛,本文利用Prim算法和Kruskal算法思想進行詳細的程序設計與求解驗證。
2.1 Prim算法
2.2 Kruskal算法
3 算法實現描述
3.1 Prim算法實現描述
根據Prim算法的思想和僞代碼,在程序開始時需要給定一個連通網並給出一個初始頂點。接着從最小生成樹邊集合擴展的角度,從剩餘結點和邊中選擇出權值最小的邊,分別加入生成樹的頂點集合和邊集合。由於對於連通網其生成樹總是存在的,因此根據生成樹的性質,對於N個結點的連通網,需要N-1條邊是的任意兩個結點之間相互連通,那麼算法結束的條件滿足經過N-1此迭代,並在每一次迭代中選擇出權值最小的邊。如果在任意一次迭代過程中,不存在由已經加入生成樹和剩餘頂點集之間取值最小的邊,則該連通網的輸入數據存在錯誤導致圖不連通。
爲了方便實現邊信息的表示,定義一個結構體類型的邊結點edgeNode,該結點中存儲邊的起始頂點from、終點頂點to以及邊的權值cost,同時定義鄰接矩陣AdjMatrix和邊集合數組edgeSet。
爲了表述普利姆算法邊和頂點的加入過程,使用流程圖[8]來表示整個程序各實現步驟之間的邏輯關係,普利姆算法程序運行流程圖如下:
3.2 Kruakal算法實現描述
根據Kruskal算法的思想和僞代碼,程序在開始的時候需要對連通網中的邊按照權值排序,接着從邊集合擴展的角度,從剩餘邊集中選擇最小的邊,若所選邊加入後不構成環路,則分別將邊和頂點加入生成樹的頂點集合和邊集合。由於無向連通網的生成樹總是存在的,根據生成樹性質,對於N個結點的連通圖,需要N-1條邊使得任意兩個結點之間相互連通,因此算法結束的條件是從邊集中選擇N-1條邊。如果所有的邊遍歷完,選擇邊的數量小於N-1,則該連通網的輸入數據存在錯誤導致圖不連通。
4 算法實現及主要函數模塊說明
爲了實現Prim算法和Kruskal算法,程序中定義了邊結點用來表示一條邊的兩個頂點及權值數據,邊結點edgeNode定義如下:
typedef struct edgeNode
{
int from,to;
int cost;
}
EDGENODE;
4.1 Prim算法及主要的功能函數模塊說明
(1)creatMatrix函數模塊
函數原型:void creatMatrix(int **AdjMatrix,int n,int e);
函數功能:以文件讀入或者鍵盤輸入的方式構造鄰接矩陣,AdjMatrix表示鄰接矩陣,n和e分別表示圖的頂點數和邊數。
(2)printMatrix函數模塊
函數原型:void printMatrix(int **AdjMatrix,int n);
函數功能:輸出鄰接矩陣,AdjMatrix表示鄰接矩陣,n表示圖的頂點數。
(3)initEdgeSet函數模塊
函數原型:void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);
函數功能:將start與其他頂點之間的權值存放到候選邊集合edgeSet中。
(4)chooseEdge函數模塊
函數原型:int chooseEdge(EDGENODE *edgeSet,int n,int index);
函數功能:從候選邊集edgeSet中選出最小邊結點,其中 index爲edgeSet選取邊時下標的起始位置。
(5)modfiyEdgeSet函數模塊
函數原型:void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to);
函數功能:新加入結點後,調整候選邊集edgeSet中的待選邊結點,其中to爲新加入到中的頂點編號。
(6)primMst最小生成樹函數模塊
函數原型:void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);
函數功能:通過頂點從候選邊集中選取最小邊構造最小生成樹。
(7)printMst最小生成樹輸出函數模塊
函數原型:void printMst(EDGENODE *edgeSet,int n);
函數功能:輸出最終最小生成樹中的選取的邊和最小權值和。