最小生成樹: 乙個連通圖的生成樹是乙個極小連通子圖,它含有圖中全部頂點,但只有足以構成一棵樹的n-1條邊。這種構造連通網的最小代價生成樹稱為最小生成樹,詳見資料結構之圖(術語、儲存結構、遍歷)
。求連通網的最小生成樹有兩種經典方法:普里姆(prime)演算法和克魯斯卡爾(kruskal)演算法。
假設n=(v,)是連通網,te是n上最小生成樹中邊的集合。從v中任選乙個頂點u0,演算法從u=(u0∈v),te={}開始,重複執行以下步驟:
在所有u∈u、v∈v-u的邊(u, v)∈e中找一條代價最小的邊(u, vi)併入集合te,同時將vi併入u,直至u=v為止。
此時te中必有n-1條邊,則t=}即為n的最小生成樹。
需要用到兩個輔助陣列:
lowcost[max_vem]:儲存從u到v-u的具有最小代價邊上的權——lowcost[i] = min
adjvex[max_vem]:儲存從u到v-u的具有最小代價邊(u,vi)依附在u中的頂點u的下標——adjvex[i] =
給定如下乙個無向網:
根據上述prime演算法描述,求其最小生成樹的過程如下:
最後得到如下最小生成樹:
//普里姆(prime)演算法
void minispantree_prime(graph *g, vertextype u0)
} int lowcost[max_vex]; //儲存從u到v-u的具有最小代價邊上的權——lowcost[i] = min
v0 = k = locatevex(g, u0); //定位開始的頂點u0在頂點陣列中的下標號
assert(k != -1);
//adjvex[k] = k; //初始化第乙個頂點下標為k
lowcost[k] = 0; //初始,u=
for (i = 0; i < g->vexnum; i++) }
for (i = 0; i < g->vexnum; i++)
min = infinity;
for (j = 0, k = 0; j < g->vexnum; j++)
}//printf("(%d,%d) ", adjvex[k], k); //列印當前頂點中權值最小的邊:
//g->vexs[adjvex[k]]∈u,g->vexs[k]∈v-u
printf("(%c,%c) ", g->vexs[adjvex[k]], g->vexs[k]);
lowcost[k] = 0; //第k頂點併入u集
for (j = 0; j < g->vexnum; j++)
}} putchar('\n');
}
執行截圖:
分析:鄰接矩陣實現的普里姆演算法的時間複雜度為o(n^2),與網中的邊數無關,適用於求邊稠密的網的最小生成樹。
假設連通網n=},令最小生成樹的初始狀態為只有n個頂點而無邊的非連通圖t=},圖中的每個頂點自成乙個連通分量。在e中選擇代價最小的邊,若改邊依附的頂點落在t中不同的連通分量上,則將次邊加入到t中,否則捨去此邊而選擇下一條代價i最小的邊。以此類推,直到t中所有頂點都在同乙個連通分量上為止。
kruskal演算法主要考慮是否會形成環路。在實際的**編寫中,一般採用邊集陣列這一資料結構:
//邊集陣列
#define max_edge 100 //最大邊數
typedef struct
edge;
我們可以通過程式將鄰接矩陣通過程式轉化為邊集陣列,並且對它們的按權值從小到大排序。如下圖所示。
//將鄰接矩陣結構轉化成邊集
void convert(graph *g, edge edge)
#if 0
printf("排序前:\n");
printf(" \tbeign\tend\tweight\n");
for(i = 0; i < k; i++)
#endif
insertsort(edge, k);
#if 1
printf("排序後:\n");
printf(" \tbeign\tend\tweight\n");
for(i = 0; i < k; i++)
#endif
}//按權值大小對邊集陣列edge從小至大排序
void insertsort(edge edge, int k)
edge[j + 1] = tmp;
} }}//查詢連線頂點的尾部
int find(int *parent, int f)
return f;
}//克魯斯卡爾演算法實現
void minispantree_kruskal(graph *g)
for(i = 0; i < g->arcnum; i++) //迴圈每一條邊 }
putchar('\n');
}
執行截圖:
不考慮鄰接矩陣或鄰接表轉化為邊集陣列的時間開銷,克魯斯卡爾演算法的find函式由邊數e決定,時間複雜度為o(loge),而外面有乙個for迴圈e次,所以克魯斯卡爾演算法的時間複雜度為o(eloge),相對prime演算法而言,適合於求邊稀疏的網的最小生成樹。
參考:這篇文章的url提示不對呀 「** 文章包含被禁用的url,無法儲存和發布。」 ,沒法給出參考鏈結了
資料結構(c語言版)
完整的測試**:
C 資料結構之最小生成樹
最小生成樹是圖的一部分,一般求最小生成樹用prim演算法和kruskal演算法。對於prim演算法,思想是 在訪問過的頂點和未訪問的頂點之間選擇權值最小的邊。prim演算法是基於頂點的操作,適合於頂點較少,邊較多的圖。對於kruskal演算法,思想是 直接從圖中選擇權值最小的邊,並且已選擇的邊不能構...
資料結構 最小生成樹
生成樹 乙個連通圖的最小連通子圖稱作該圖的生成樹。有n個結點的連通圖的生成樹有n個結點和n 1條邊。乙個有n個結點的連通圖的生成樹是原圖的極小連通子圖,它包含原圖中的所有n個結點,並且有保持圖連通的最少的邊。由生成樹的定義可知 若在生成樹中刪除一條邊,就會使該生成樹因變成非連通圖而不再滿足生成樹的定...
資料結構(最小生成樹)
對於乙個無相連通網,他的所有生成樹中必有一棵邊的權值總和最小的生成樹,稱之為最小代價生成樹,簡稱最小生成樹。最小生成樹必須滿足三個條件 1 構造的最小生成樹必須包括n個頂點 2 構造的最小生成樹有且僅有n 1條邊 3 構造的最小生成樹中不存在迴路。普利姆演算法 prim 假設g v,e 為一無向連通...