上次我們介紹了圖的鄰接表存儲結構基本操作的實現,這次介紹基於鄰接矩陣的兩種最小生成樹算法的實現。
還是老規矩:
程序在碼雲上可以下載。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git
最小生成樹有兩個經典的算法:
1.普里姆算法:主要是針對頂點操作,選最小鄰接邊組成生成樹。
2.克魯斯卡爾算法:主要針對邊操作,所有邊裏選最小權值的邊組成生成樹。
本次最小生成樹共用到以下源文件,有一些已經在之前的文章介紹過。還是和以前一樣,所有源文件需要放在同一目錄下編譯。
my_constants.h 各種狀態碼定義
MGraph.h 圖的鄰接矩陣存儲結構表示定義
MGraph.cpp 基於鄰接矩陣的基本操作實現
MiniSpanTree.cpp 普利姆算法和克魯斯卡爾算法的實現(含有動態演示代碼)
最小生成樹測試.cpp 主函數,調用算法完成最小生成樹的動態演示
鄰接矩陣在《數據結構編程筆記十八:第七章 圖 圖的鄰接矩陣存儲表示及各基本操作的實現》一文有所介紹,my_constants.h、MGraph.h 和MGraph.cpp三個源文件與此文中的同名源文件內容完全一致,沒有修改。這裏不再重複貼了(否則文章會很長,不能突出重點),但在碼雲上你可以下載到全部源文件,我會把它放在一個目錄下。
本次只貼最小生成樹的核心代碼和主函數:
源文件:MiniSpanTree.cpp
//-------------- 最小生成樹 ----------------------------
//-------------------輔助數組的定義-------------------------------
struct Record{
VertexType adjvex; //頂點
VRType lowcost; //最低代價
}closedge[MAX_VERTEX_NUM];
/*
函數:printColsedge
參數:Record closedge[] 計算最小生成樹的輔助數組closedge
int n 頂點數
返回值:無
作用:打印closedge數組
*/
void printColsedge(Record closedge[], MGraph G) {
//打印i一行
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
printf("| i |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %2d |", i);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
//頂點值
printf("| 頂點 |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %2d |", G.vexs[i]);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
//打印adjvex一行
printf("| adjvex |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %3d |", closedge[i].adjvex);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
//打印lowcost一行
printf("| lowcost |");
for(int i = 0; i < G.vexnum; i++) {
if(closedge[i].lowcost != INFINITY) {
printf(" %3d |", closedge[i].lowcost);
}//if
else {
printf(" ∞ |");
}//else
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
}//printColsedge
/*
函數:minimum
參數:Record closedge[] 計算最小生成樹的輔助數組closedge
返回值:選出頂點的序號
作用:從closedge數組中選出符合條件的最小生成樹的下一頂點
*/
int minimum(Record closedge[]){
//min是從closedge數組中選出的最小代價邊的另一個頂點在圖中的位置
//reserve是輔助參與比較的最小代價,初始值爲65535,
//每一次發現代價比它更小的邊則reserve會被更新爲新的最小代價
int reserve = 65535, min = 0;
for(int i = 1; i < MAX_VERTEX_NUM; i++) {
//沒有訪問過但是存在路徑並且代價更小(比記錄最小代價的reserve還小)
if(closedge[i].lowcost < reserve && closedge[i].lowcost > 0){
printf("->發現比reserve = %d更小的權值:closedge[%d].lowcost = %d !\n",
reserve, i, closedge[i].lowcost);
//reserve更新爲新的最小代價
reserve = closedge[i].lowcost;
//min更新爲最小代價邊的另一頂點在圖中的位置
min = i;
}//if
}//for
return min;
}//minimum
/* (普里姆算法求最小生成樹)
函數:MiniSpanTree_PRIM
參數:MGraph G 圖G
返回值:無
作用:用普里姆算法從第u個頂點出發構造網G的最小生成樹T,輸出T的各條邊
記錄從定點集U到V-U的代價最小的邊的輔助數組定義
*/
void MiniSpanTree_PRIM(MGraph G, VertexType u){
//k是出發頂點u在圖中的序號
int k = LocateVex(G, u);
//輔助數組初始化
for(int j = 0; j < G.vexnum; ++j) {
//j指示的頂點不是出發頂點
if(j != k){
//{adjvex, lowcost}
//設置鄰接點爲起始頂點u
closedge[j].adjvex = u;
//設置closedge數組初始最小代價,其實就是
//直接拷貝第G.arcs二維數組的第k行
closedge[j].lowcost = G.arcs[k][j].adj;
}//if
}//for
//設置出發點u的最小代價爲0,此時U={u}
closedge[k].lowcost = 0;
printf("\n->最小生成樹從頂點%d開始,所以該頂點此時已被加入最小生成樹頂點集合!\n\n", G.vexs[k]);
//從頂點u開始生成最小生成樹
for(int i = 1; i < G.vexnum; ++i) {
printf("\n->這是第%d趟循環:\n" , i);
printf("->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):\n");
//打印closedge數組
printColsedge(closedge, G);
printf("->開始求最小生成樹的下一頂點:\n");
//求出最小生成樹的下一個結點:第k頂點
//此時closedge[k].lowcost= MIN{ closedge[vi].lowcost
// | closedge[vi].lowcost > 0, vi ∈V-U}
k = minimum(closedge);
printf("->求得最小生成樹的下一頂點爲:%d,下一頂點序號k = %d, 最小代價爲:%d\n", G.vexs[k], k, closedge[k].lowcost);
//輸出生成樹的邊及其權值
printf("\n->得到最小生成樹的一條新邊: %2d <--- %2d ---> %2d \n\n", closedge[k].adjvex,
closedge[k].lowcost, G.vexs[k]);
//第k頂點併入U集
closedge[k].lowcost = 0;
//查找k的鄰接頂點中代價更小的邊對應的鄰接頂點
//將新頂點併入U後重新選擇最小邊
//選出一個頂點k之後需要更新closedge數組中最小邊信息
for(int j = 1; j < G.vexnum; ++j) {
//發現代價更小的邊就更新closedge數組
//若沒有發現則保持原值不變
if(G.arcs[k][j].adj < closedge[j].lowcost){
printf("從%d的所有鄰接頂點中發現有G.arcs[%d][%d].adj = %d 比 closedge[%d].lowcost = %d 更小,更新closedge數組!\n",
G.vexs[k], k, j, G.arcs[k][j].adj, j, closedge[j].lowcost);
//更新closedge數組的鄰接點信息adjvex
closedge[j].adjvex = G.vexs[k];
//更新closedge數組的最小邊信息lowcost
closedge[j].lowcost = G.arcs[k][j].adj;
}//if
}//for
printf("\n->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):\n");
//打印closedge數組
printColsedge(closedge, G);
system("pause");
}//for
}//MiniSpanTree_PRIM
/*
函數:printSet
參數:int set[] 保存頂點所屬集合狀態的數組set
MGraph G 圖G
返回值:無
作用:打印set數組
*/
void printSet(int set[], MGraph G) {
//打印i一行
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
printf("| i |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %2d |", i);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
//頂點值
printf("| 頂點 |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %2d |", G.vexs[i]);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
//打印set一行
printf("| set |");
for(int i = 0; i < G.vexnum; i++) {
printf(" %3d |", set[i]);
}//for
printf("\n");
printf("+----------+");
for(int i = 0; i < G.vexnum; i++) {
printf("-----+");
}//for
printf("\n");
}//printSet
/* (克魯斯卡爾算法求最小生成樹)
函數:MiniSpanTree_kruskal
參數:MGraph G 圖G
返回值:無
作用:克魯斯卡爾算法求最小生成樹
*/
void MiniSpanTree_kruskal(MGraph G) {
int set[MAX_VERTEX_NUM];
int k = 0, a = 0, b = 0, setb, min = G.arcs[a][b].adj;
//set[]初態,各頂點分別屬於各個集合
for(int i = 0; i < G.vexnum; i++) {
set[i] = i;
}//for
printf("->set數組初始狀態(各頂點分別屬於各個集合):\n");
printSet(set, G);
printf("最小代價生成樹的各條邊及權值爲:\n");
//最小生成樹的邊數應該有n-1條邊,其中n爲頂點數
while(k < G.vexnum-1) {
printf("\n->這是第%d趟循環,尋找更小權值的邊:\n", k + 1);
//尋找最小權值的邊
for(int i = 0; i < G.vexnum; ++i) {
//無向網,只在上三角查找
for(int j = i + 1; j < G.vexnum; ++j) {
//發現比min更小的權值
if(G.arcs[i][j].adj < min) {
printf("->發現比min = %d 更小的權值:%d,修改min爲該值!\n", min, G.arcs[i][j].adj);
//最小權值
min = G.arcs[i][j].adj;
//邊的一個頂點
a = i;
//邊的另一個頂點
b = j;
}//if
}//for
}//for
//邊的兩頂點不屬於同一集合
if(set[a] != set[b]) {
//輸出該邊
printf("->找到一條最小生成樹的新邊:%d <-- %d --> %d\n", G.vexs[a], G.arcs[a][b].adj, G.vexs[b]);
}//if
//重置min爲極大值
min = G.arcs[a][b].adj = INFINITY;
//邊的兩頂點不屬於同一集合
if(set[a] != set[b]) {
//邊數+1
k++;
//保存setb的值
setb = set[b];
//將頂點b所在集合併入頂點a集合中
for(int i = 0; i < G.vexnum; i++) {
//不可以直接set[i] == set[b]作爲比較條件,因爲i可能等於b!
//一旦set[b]被修改,那麼set[b]後面的元素將無法正確合併
if(set[i] == setb) {
printf("->合併頂點%d到頂點%d的集合中,注意set數組的變化。\n", G.vexs[i], G.vexs[a]);
set[i] = set[a];
}//if
}//for
printf("->set數組修改後的值:\n");
printSet(set, G);
}//if
}//while
printf("->set數組初最終狀態(無向連通網所有頂點應該都在一個集合裏):\n");
printSet(set, G);
}//MiniSpanTree_kruskal
源文件:最小生成樹測試.cpp
//**************************引入頭文件*****************************
#include <stdio.h> //使用了標準庫函數
#include <stdlib.h> //使用了動態內存分配函數
#include "my_constants.h" //引入自定義的符號常量,主要是狀態碼
#include "MGraph.h" //引入圖的鄰接矩陣表示法的基本定義
#include "MGraph.cpp" //引入圖的主要操作
#include "MiniSpanTree.cpp" //引入最小生成樹實現
//----------------------主函數----------------------
int main(int argc, char *argv[]){
printf("\n-------------最小生成樹(鄰接矩陣)測試程序--------------\n\n");
//圖G
MGraph G;
//臨時變量,保存輸入的頂點數
int n;
//圖的創建
printf("->測試圖的創建(最小生成樹操作要求圖的類型是無向連通網,請選擇3):\n");
CreateGraph(G);
//打印鄰接矩陣
printf("\n->創建成功後圖的鄰接矩陣:\n\n");
PrintAdjMatrix(G);
//若爲無向網,求其最小生成樹
if(G.kind == UDN){
printf("\n->測試普利姆算法求無向網的最小生成樹\n");
MiniSpanTree_PRIM(G, G.vexs[0]);
printf("\n->測試克魯斯卡爾算法求無向網的最小生成樹\n");
MiniSpanTree_kruskal(G);
}//if
else {
printf("\n->您生成的不是無向網,無法求最小生成樹!\n");
}//else
//測試銷燬
printf("\n->測試銷燬圖: ");
DestroyGraph(G);
printf("成功!\n");
printf("演示結束,程序退出!\n");
return 0;
}
程序運行輸入的數據和輸出(輸入的無向圖來自教材P174頁,你可以對比圖7.17的數據和輸出的數據是否一致):
-------------最小生成樹(鄰接矩陣)測試程序--------------
->測試圖的創建(最小生成樹操作要求圖的類型是無向連通網,請選擇3):
請輸入您想構造的圖的類型:有向圖輸入0,有向網輸入1,無向圖輸入2,無向網輸入3):3
請依次輸入無向網G的頂點數,弧數,用逗號隔開
6,10
請依次輸入無向網G的頂點名稱,用空格隔開
1 2 3 4 5 6
請依次輸入無向網G每條弧依附的兩頂點名稱及權值,輸完一組按回車
1 2 6
1 4 5
1 3 1
3 2 5
3 4 5
3 5 6
3 6 4
2 5 3
4 6 2
5 6 6
->創建成功後圖的鄰接矩陣:
1 2 3 4 5 6
+------------------------------
1 | ∞ 6 1 5 ∞ ∞
|
2 | 6 ∞ 5 ∞ 3 ∞
|
3 | 1 5 ∞ 5 6 4
|
4 | 5 ∞ 5 ∞ ∞ 2
|
5 | ∞ 3 6 ∞ ∞ 6
|
6 | ∞ ∞ 4 2 6 ∞
|
->測試普利姆算法求無向網的最小生成樹
->最小生成樹從頂點1開始,所以該頂點此時已被加入最小生成樹頂點集合!
->這是第1趟循環:
->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 1 | 1 | 1 | 1 | 1 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 6 | 1 | 5 | ∞ | ∞ |
+----------+-----+-----+-----+-----+-----+-----+
->開始求最小生成樹的下一頂點:
->發現比reserve = 65535更小的權值:closedge[1].lowcost = 6 !
->發現比reserve = 6更小的權值:closedge[2].lowcost = 1 !
->求得最小生成樹的下一頂點爲:3,下一頂點序號k = 2, 最小代價爲:1
->得到最小生成樹的一條新邊: 1 <--- 1 ---> 3
從3的所有鄰接頂點中發現有G.arcs[2][1].adj = 5 比 closedge[1].lowcost = 6 更小,更新closedge數組!
從3的所有鄰接頂點中發現有G.arcs[2][4].adj = 6 比 closedge[4].lowcost = 65535 更小,更新closedge數組!
從3的所有鄰接頂點中發現有G.arcs[2][5].adj = 4 比 closedge[5].lowcost = 65535 更小,更新closedge數組!
->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 1 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 5 | 6 | 4 |
+----------+-----+-----+-----+-----+-----+-----+
請按任意鍵繼續. . .
->這是第2趟循環:
->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 1 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 5 | 6 | 4 |
+----------+-----+-----+-----+-----+-----+-----+
->開始求最小生成樹的下一頂點:
->發現比reserve = 65535更小的權值:closedge[1].lowcost = 5 !
->發現比reserve = 5更小的權值:closedge[5].lowcost = 4 !
->求得最小生成樹的下一頂點爲:6,下一頂點序號k = 5, 最小代價爲:4
->得到最小生成樹的一條新邊: 3 <--- 4 ---> 6
從6的所有鄰接頂點中發現有G.arcs[5][3].adj = 2 比 closedge[3].lowcost = 5 更小,更新closedge數組!
->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 2 | 6 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
請按任意鍵繼續. . .
->這是第3趟循環:
->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 2 | 6 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
->開始求最小生成樹的下一頂點:
->發現比reserve = 65535更小的權值:closedge[1].lowcost = 5 !
->發現比reserve = 5更小的權值:closedge[3].lowcost = 2 !
->求得最小生成樹的下一頂點爲:4,下一頂點序號k = 3, 最小代價爲:2
->得到最小生成樹的一條新邊: 6 <--- 2 ---> 4
->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 0 | 6 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
請按任意鍵繼續. . .
->這是第4趟循環:
->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 3 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 5 | 0 | 0 | 6 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
->開始求最小生成樹的下一頂點:
->發現比reserve = 65535更小的權值:closedge[1].lowcost = 5 !
->求得最小生成樹的下一頂點爲:2,下一頂點序號k = 1, 最小代價爲:5
->得到最小生成樹的一條新邊: 3 <--- 5 ---> 2
從2的所有鄰接頂點中發現有G.arcs[1][4].adj = 3 比 closedge[4].lowcost = 6 更小,更新closedge數組!
->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 2 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 0 | 0 | 0 | 3 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
請按任意鍵繼續. . .
->這是第5趟循環:
->更新closedge數組之前,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 2 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 0 | 0 | 0 | 3 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
->開始求最小生成樹的下一頂點:
->發現比reserve = 65535更小的權值:closedge[4].lowcost = 3 !
->求得最小生成樹的下一頂點爲:5,下一頂點序號k = 4, 最小代價爲:3
->得到最小生成樹的一條新邊: 2 <--- 3 ---> 5
->更新closedge數組之後,closedge數組的值(adjvex是頂點序號,不是頂點名稱,lowcost = 0表示該頂點已被納入最小生成樹的頂點集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| adjvex | 0 | 3 | 1 | 6 | 2 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
| lowcost | 0 | 0 | 0 | 0 | 0 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
請按任意鍵繼續. . .
->測試克魯斯卡爾算法求無向網的最小生成樹
->set數組初始狀態(各頂點分別屬於各個集合):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
最小代價生成樹的各條邊及權值爲:
->這是第1趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:1,修改min爲該值!
->找到一條最小生成樹的新邊:1 <-- 1 --> 3
->合併頂點3到頂點1的集合中,注意set數組的變化。
->set數組修改後的值:
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 0 | 1 | 0 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
->這是第2趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:5,修改min爲該值!
->發現比min = 5 更小的權值:3,修改min爲該值!
->發現比min = 3 更小的權值:2,修改min爲該值!
->找到一條最小生成樹的新邊:4 <-- 2 --> 6
->合併頂點6到頂點4的集合中,注意set數組的變化。
->set數組修改後的值:
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 0 | 1 | 0 | 3 | 4 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
->這是第3趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:5,修改min爲該值!
->發現比min = 5 更小的權值:3,修改min爲該值!
->找到一條最小生成樹的新邊:2 <-- 3 --> 5
->合併頂點5到頂點2的集合中,注意set數組的變化。
->set數組修改後的值:
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 0 | 1 | 0 | 3 | 1 | 3 |
+----------+-----+-----+-----+-----+-----+-----+
->這是第4趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:5,修改min爲該值!
->發現比min = 5 更小的權值:4,修改min爲該值!
->找到一條最小生成樹的新邊:3 <-- 4 --> 6
->合併頂點4到頂點3的集合中,注意set數組的變化。
->合併頂點6到頂點3的集合中,注意set數組的變化。
->set數組修改後的值:
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 0 | 1 | 0 | 0 | 1 | 0 |
+----------+-----+-----+-----+-----+-----+-----+
->這是第5趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:5,修改min爲該值!
->這是第5趟循環,尋找更小權值的邊:
->發現比min = 65535 更小的權值:6,修改min爲該值!
->發現比min = 6 更小的權值:5,修改min爲該值!
->找到一條最小生成樹的新邊:2 <-- 5 --> 3
->合併頂點1到頂點2的集合中,注意set數組的變化。
->合併頂點3到頂點2的集合中,注意set數組的變化。
->合併頂點4到頂點2的集合中,注意set數組的變化。
->合併頂點6到頂點2的集合中,注意set數組的變化。
->set數組修改後的值:
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 1 | 1 | 1 | 1 | 1 | 1 |
+----------+-----+-----+-----+-----+-----+-----+
->set數組初最終狀態(無向連通網所有頂點應該都在一個集合裏):
+----------+-----+-----+-----+-----+-----+-----+
| i | 0 | 1 | 2 | 3 | 4 | 5 |
+----------+-----+-----+-----+-----+-----+-----+
| 頂點 | 1 | 2 | 3 | 4 | 5 | 6 |
+----------+-----+-----+-----+-----+-----+-----+
| set | 1 | 1 | 1 | 1 | 1 | 1 |
+----------+-----+-----+-----+-----+-----+-----+
->測試銷燬圖: 成功!
演示結束,程序退出!
--------------------------------
Process exited with return value 0
Press any key to continue . . .
總結:
普利姆算法主要針對的是頂點,與圖中的邊數無關,適合求稠密網(邊比較多的網)的最小生成樹。
克魯斯卡爾主要針對邊,與圖中頂點數無關,適合求稀疏網(邊較少的網)的最小生成樹
下次的文章會介紹最短路徑兩種算法的實現,感謝大家一直以來的關注。再見!