前面對 圖的存儲 和 **圖的遍歷(廣度優先/深度優先)**作了簡單的學習和了解,本篇文章,學習一下最小生成樹的問題,以及對應解決這個問題的兩種算法 普里姆算法 和 克魯斯卡爾算法面試
首先看下面一道面試題:算法
假設目前有
N
個頂點,每一個頂點鏈接的路徑不同,設計一個算法,快速查找出能覆蓋全部頂點的路徑。數組
其實這個問題並非求解兩點之間的最短路徑,而是設計一個路線,能覆蓋全部的頂點。bash
以下連通圖: 數據結構
那麼覆蓋全部頂點的路徑有一下幾種學習
方法一ui
V0 ——> V5 ——> V4 --> V3 --> V2 -->V1 -->V8 --> V6 -->V7
spa
權重:11 + 26 + 20 + 22 + 18 + 21 + 24 + 19 = 161設計
方案二code
V2 ——> V8 ——> V1 --> V0 --> V5 -->V6 -->V7 --> V3 -->V4
權重:8 + 12 + 10 + 11 + 17 + 19 + 16 + 7 = 100
方案三
權重:8 + 12 + 10 + 11 + 16 + 19 + 16 + 7 = 99
由此能夠看出,方法三是最優的方案,這就是最小生成樹。
最小生成樹:把構成連通網的最小代價的生成樹稱之爲最小生成樹。即假設有N
個頂點,用N-1
條邊,鏈接全部頂點,並且權重的和最小的路徑。
普里姆算法思路:
1. 定義兩個數組,adjvew 用來保存相關頂點下標,lowcost 保存頂點之間的權值。
2. 初始化兩個數組,將與 V0 相關的 V1-V8 的全部頂點的權值賦值給 lowcost
adjvew[1-8],都賦值爲 0,表示都是與 V0 相關的頂點(後面循環修改)
3. 循環 lowcost 數組,根據權值,找到權值最新的頂點的下標 k
4. 更新 lowcost 數組
5. 循環全部頂點,找到與下標爲 k 的頂點,有關係的頂點,並更新 lowcost 數組和 adjvew 數組
注意:
更新 lowcost 數組的條件
1. 與下標爲 k 的頂點之間有鏈接
2. 當前下標爲 j 的頂點是否加入最小生成樹
3. 下標爲 k 的頂點與下標爲 j 的頂點的權值比較,小於,則更新,
簡單說就是要比較以前存儲的權值,小於,則更新。
複製代碼
接下來,咱們詳細的解析一下上面的思路:
lowcost
和 adjvew
lowcost
數組(將與 V0
相關的 V1-V8
的全部頂點的權值賦值給 lowcost
)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 10 | ∞ | ∞ | ∞ | 11 | ∞ | ∞ | ∞ |
默認將V0
加入到最小生成樹中,lowcost[0] = 0
,10
和 11
表示頂點V0 鏈接頂點V1
和V5
的權值。
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
而後開始循環(從
i = 1
開始,默認第一個已經加入最小樹)
第一次循環 i = 1
由上面的表格看出,10
是最小的權值,
此時,k = 1
,在lowcost
數組中10
最小。且知足更新 lowcost
數組的三個條件,
因此,lowcost[1] = 0
, 表示 V1
已經加入最小生成樹,並打印信息
lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | ∞ | ∞ | ∞ | 11 | ∞ | ∞ | ∞ |
而後,循環全部頂點,找到下標爲k
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V2 未加入最小生成樹,且權值 18 < ∞,lowcost【2】= 18,adjvew【2】= 1
V8 未加入最小生成樹,且權值 12 < ∞,lowcost【8】= 12,adjvew【8】= 1
V6 未加入最小生成樹,且權值 16 < ∞,lowcost【6】= 16,adjvew【6】= 1
複製代碼
lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 18 | ∞ | ∞ | 11 | 16 | ∞ | 12 |
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
18,16,12
對應V二、V六、V8
,是針對V1
相關的頂點,
1
是由於 k = 1
,表示與V1
相連的頂點是V二、V六、V8
第二次循環 i = 2
從 lowcost
中找到 權值最小 11
的 j = 5
,即是 k = 5
因此,lowcost[5] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 5
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V6 未加入最小生成樹,且權值 17 > 16,不更新
V4 未加入最小生成樹,且權值 26 < ∞,lowcost【4】= 26,adjvew【4】= 5
V3 未加入最小生成樹,且權值 ∞ < ∞,不更新
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 18 | ∞ | 26 | 0 | 16 | ∞ | 12 |
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 0 | 5 | 0 | 1 | 0 | 1 |
1
,表示與V1
相連的頂點V二、V六、V8
,
5
是由於 k = 5
,表示與V5
相連的頂點是V4
第三次循環 i = 3
從 lowcost
中找到 權值最小12
的 j = 8
,即是 k = 8
因此,lowcost[8] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 8
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V2 未加入最小生成樹,且權值 8 < 18,lowcost【2】= 8,adjvew【2】= 8
V3 未加入最小生成樹,且權值 21 < ∞,lowcost【3】= 21,adjvew【3】= 8
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 21 | 26 | 0 | 16 | ∞ | 0 |
V0、V一、V五、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 8 | 5 | 0 | 1 | 0 | 1 |
1
,表示與V1
相連的頂點V六、V8
,
5
,表示與V5
相連的頂點是V4
8
是由於 k = 8
,表示與V8
相連的頂點是V二、V3
第四次循環 i = 4
從 lowcost
中找到 權值最小8
的 j = 2
,即是 k = 2
因此,lowcost[2] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 2
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V3 未加入最小生成樹,且權值 22 > 21,不更新
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 21 | 26 | 0 | 16 | ∞ | 0 |
V0、V一、V五、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 8 | 5 | 0 | 1 | 0 | 1 |
1
,表示與V1
相連的頂點V六、V8
, 5
,表示與V5
相連的頂點是V4
8
是由於 k = 8
,表示與V8
相連的頂點是V二、V3
第五次循環 i = 5
從 lowcost
中找到 權值最小16
的 j = 6
,即是 k = 6
因此,lowcost[6] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 6
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V7 未加入最小生成樹,且權值 19 < ∞,lowcost【7】= 19,adjvew【7】= 6
V3 未加入最小生成樹,且權值 22 > 21,不更新
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 21 | 26 | 0 | 0 | 19 | 0 |
V0、V一、V二、V五、V六、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 8 | 5 | 0 | 1 | 6 | 1 |
1
,表示與V1
相連的頂點V六、V8
,
5
,表示與V5
相連的頂點是V4
8
,表示與V8
相連的頂點是V二、V3
6
是由於 k = 6
,表示與V6
相連的頂點是V7
第六次循環 i = 6
從 lowcost
中找到 權值最小19
的 j = 7
,即是 k = 7
因此,lowcost[7] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 7
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V4 未加入最小生成樹,且權值 7 < 26,lowcost【4】= 7,adjvew【4】= 7
V3 未加入最小生成樹,且權值 16 < 21,lowcost【3】= 16,adjvew【3】= 7
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 16 | 7 | 0 | 0 | 0 | 0 |
V0、V一、V二、V五、V六、V七、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 7 | 7 | 0 | 1 | 6 | 1 |
1
,表示與V1
相連的頂點V六、V8
,
8
,表示與V8
相連的頂點是V2
6
,表示與V6
相連的頂點是V7
7
是由於 k = 7
,表示與V7
相連的頂點是V3,V4
第七次循環 i = 7
從 lowcost
中找到 權值最小7
的 j = 4
,即是 k = 4
因此,lowcost[4] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 4
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V3 未加入最小生成樹,且權值 20 > 16,不更新
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 16 | 0 | 0 | 0 | 0 | 0 |
V0、V一、V二、V四、V五、V六、V七、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 7 | 7 | 0 | 1 | 6 | 1 |
1
,表示與V1
相連的頂點V六、V8
,
8
,表示與V8
相連的頂點是V2
6
,表示與V6
相連的頂點是V7
7
是由於 k = 7
,表示與V7
相連的頂點是V3,V4
第八次循環 i = 8
從 lowcost
中找到 權值最小16
的 j = 3
,即是 k = 3
因此,lowcost[3] = 0
,加入到最小生成樹中,並打印信息
而後,循環全部頂點,找到下標爲k = 3
頂點各邊權值小於此前這些頂點未被加入生成樹權值,而後更新lowcost
數組和adjvew
數組
V3 未加入最小生成樹,且權值 20 > 16,不更新
複製代碼
此時,lowcost
數組
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
V0、V一、V二、V三、V四、V五、V六、V七、V8
都已經加入最小生成樹
adjvew
數組(都賦值爲 0,表示都是與 V0 相關的頂點)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 7 | 7 | 0 | 1 | 6 | 1 |
1
,表示與V1
相連的頂點V六、V8
,
8
,表示與V8
相連的頂點是V2
6
,表示與V6
相連的頂點是V7
7
是由於 k = 7
,表示與V7
相連的頂點是V3,V4
代碼實現:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 20
typedef int Status;
typedef struct {
int arc[MAXVEX][MAXVEX];
int numVertexes;
int numEdges;
}MGraph;
/* Prim算法生成最小生成樹 */
void MiniSpanTree_Prim(MGraph G)
{
int min, i, j, k = 0;
int sum = 0;
int adjvex[MAXVEX]; // 保存相關頂點下標
int lowcost[MAXVEX]; // 保存相關頂點的權重
// 初始化第一個權值爲0 ,將V0加入生成最小樹
lowcost[0] = 0;
// 初始化第一個頂點的下標爲0
adjvex[0] = 0;
// 初始化
for (i = 1; i < G.numVertexes; i++) {
// 將v0頂點與之有邊的權值存入數組
lowcost[i] = G.arc[0][i];
// 初始化默認都爲v0的下標
adjvex[i] = 0;
}
// 循環除了下標爲 0 之外的所有頂點,找到z權重最小且沒有加入到s最小樹中的頂點
for (i = 1; i < G.numVertexes; i++) {
min = INFINITY;
j = 1; k = 0;
while (j < G.numVertexes) {
if (lowcost[j] != 0 && lowcost[j] < min) {
// 讓當前權值成爲最小值,更新min
min = lowcost[j];
// 當前最小值的下標賦值給 k
k = j;
}
j++;
}
}
// 打印
printf("(V%d, V%d) = %d\n", adjvex[k], k, G.arc[adjvex[k]][k]);
sum += G.arc[adjvex[k]][k];
// 當前頂點的權值設置爲0 ,標誌爲已經加入最小樹
lowcost[k] = 0;
// 循環全部頂點,找到與頂點k 相鏈接的頂點
for (j = 1; j < G.numVertexes; j++) {
if (lowcost[j] != 0 && G.arc[k][j] < lowcost[j]) {
// 將較小的權值存入lowcost相應位置
lowcost[j] = G.arc[k][j];
// 下標爲k的頂點存入adjvex
adjvex[j] = k;
}
}
printf("sum = %d\n", sum);
}
複製代碼
克魯斯卡爾算法思路:
1.將 鄰接矩陣 轉換爲 邊表數組()
2.對邊表數組根據權重值按照從小到大的順序排序
3.遍歷全部的邊,打印不閉環的邊,經過 parent 數組找到邊的鏈接信息,避免閉環
4.若是不存在閉環問題,則加入到最小生成樹中,並修改 parent 數組
複製代碼
克魯斯卡爾算法詳細解析以下:
設計以下的邊表數據結構:
/* 對邊集數組Edge結構的定義 */
typedef struct
{
int begin; // 開始
int end; // 結束
int weight; // 權重
}Edge ;
複製代碼
那麼對上面所說的圖的邊表,排序後以下:
begin | end | weight |
---|---|---|
4 | 7 | 7 |
2 | 8 | 8 |
0 | 1 | 10 |
0 | 5 | 11 |
1 | 8 | 12 |
3 | 7 | 16 |
1 | 6 | 16 |
5 | 6 | 17 |
1 | 2 | 18 |
6 | 7 | 19 |
3 | 4 | 20 |
3 | 8 | 21 |
2 | 3 | 22 |
3 | 6 | 24 |
4 | 5 | 26 |
初始化parent
數組,給初始值爲0,默頂點間認沒有鏈接
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
而後開始遍歷 排好序的邊表:
定義n
和 m
,分別表示begin
和 end
,若是 m = n
,表示 begin
和 end
鏈接,就會產生閉合的環.
第 0
次,i = 0
begin = 4,end = 7
, n = 4
, m = 7
n != m
,因此parent[4] = 7
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 1
次,i = 1
begin = 2,end = 8
, n = 2
, m = 8
n != m
,因此parent[2] = 8
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 8 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 2
次,i = 2
begin = 0,end = 1
, n = 0
, m = 1
n != m
,因此parent[0] = 1
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 8 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 3
次,i = 3
begin = 0,end = 5
, n = 0
, m = 5
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[0] = 1
,因此 n = 1
,parent[5] = 0
,直接返回 5
n != m
,因此parent[1] = 5
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 4
次,i = 4
begin = 1,end = 8
, n = 1
, m = 8
而後從parent 數組
中,能夠找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[1] = 5
,因此 n = 5
,parent[8] = 0
,直接返回 8
n != m
,因此parent[5] = 8
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 0 | 7 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 5
次,i = 5
begin = 3,end = 7
, n = 3
, m = 7
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[3] = 0
,因此 n = 3
,parent[7] = 0
,直接返回 7
n != m
,因此parent[3] = 7
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第 6
次,i = 6
begin = 1,end = 6
, n = 1
, m = 6
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[1] = 5,parent[5] = 8
,因此 n = 8
,parent[6] = 0
,直接返回 6
n != m
,因此parent[8] = 6
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 7
次,i = 7
begin = 5,end = 6
, n = 5
, m = 6
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[5] = 8,parent[8] = 6
,因此 n = 6
,parent[6] = 0
,直接返回 6
n = m
,因此不更新parent數組
,因此不能加入最小樹
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 8
次,i = 8
begin = 1,end = 2
, n = 1
, m = 2
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[1] = 5,parent[5] = 8,parent[8] = 6
,因此 n = 6
,parent[2] = 8,parent[8] = 6
,直接返回 m = 6
n = m
,因此不更新parent數組
,因此不能加入最小樹
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 9
次,i = 9
begin = 6,end = 7
, n = 6
, m = 7
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[6] = 0
,因此 n = 6
,parent[7] = 9
,直接返回 m = 6
n != m
,因此更新parent數組
,因此parent[6] = 7
,而後打印計算權重
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 7 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 10
次,i = 10
begin = 3,end = 4
, n = 3
, m = 4
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[3] = 7,parent[7] = 0
,因此 n = 7
,parent[4] = 7,parent[7] = 0
,直接返回 m = 7
n = m
,因此不更新parent數組
,因此不能加入最小樹
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 7 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 11
次,i = 11
begin = 3,end = 8
, n = 3
, m = 8
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[3] = 7,parent[7] = 0
,因此 n = 7
,parent[8] = 6,parent[6] = 7
,直接返回 m = 7
n = m
,因此不更新parent數組
,因此不能加入最小樹
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 7 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 12
次,i = 12
begin = 2,end = 3
, n = 2
, m = 3
而後從parent 數組
中,找到當前頂點的尾部下標( 幫助咱們判斷2點之間是否存在閉環問題) parent[2] = 8,parent[8] = 6,parent[6] = 7
,因此 n = 7
,parent[3] = 7,parent[7] = 0
,直接返回 m = 7
n = m
,因此不更新parent數組
,因此不能加入最小樹
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 7 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
第 13
次,i = 13
同上分析,m = n
,不更新
第 14
次,i = 14
同上分析,m = n
,不更新
parent
數組以下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 5 | 8 | 7 | 7 | 8 | 7 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
最終遍歷完全部的邊,找到最小樹
代碼實現:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 20
#define INFINITYC 65535
typedef int Status;
// 圖結構
typedef struct
{
int arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
// 邊表結構
typedef struct {
int begin;
int end;
int weight;
}Edge;
/* 交換權值以及頭和尾 */
void Swapn(Edge *edges,int i, int j)
{
int tempValue;
//交換edges[i].begin 和 edges[j].begin 的值
tempValue = edges[i].begin;
edges[i].begin = edges[j].begin;
edges[j].begin = tempValue;
//交換edges[i].end 和 edges[j].end 的值
tempValue = edges[i].end;
edges[i].end = edges[j].end;
edges[j].end = tempValue;
//交換edges[i].weight 和 edges[j].weight 的值
tempValue = edges[i].weight;
edges[i].weight = edges[j].weight;
edges[j].weight = tempValue;
}
/* 對權值進行排序 */
void sort(Edge edges[],MGraph *G)
{
//對權值進行排序(從小到大)
int i, j;
for ( i = 0; i < G->numEdges; i++)
{
for ( j = i + 1; j < G->numEdges; j++)
{
if (edges[i].weight > edges[j].weight)
{
Swapn(edges, i, j);
}
}
}
printf("邊集數組根據權值排序以後的爲:\n");
for (i = 0; i < G->numEdges; i++)
{
printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
}
}
int Find(int *parent, int f)
{
while ( parent[f] > 0)
{
f = parent[f];
}
return f;
}
/* 生成最小生成樹 */
void MiniSpanTree_Kruskal(MGraph G)
{
int i, j, n, m;
int sum = 0;
int k = 0;
int parent[MAXVEX];
Edge edges[MAXEDGE];
// 構建邊表
for (i = 0; i < G.numVertexes - 1; i++) {
for (j = 1 + i; j < G.numVertexes; j++) {
if (G.arc[i][j] < INFINITYC) {
edges[k].begin = i;
edges[k].end = j;
edges[k].weight = G.arc[i][j];
k++;
}
}
}
// 排序
sort(edges, &G);
// 初始化parent 數組爲0. 9個頂點;
for (i = 0; i < MAXVEX; i++)
parent[i] = 0;
// 循環邊表
for (i = 0; i < G.numEdges; i++) {
//獲取begin,end 在parent 數組中的信息;
//若是n = m ,將begin 和 end 鏈接,就會產生閉合的環.
n = Find(parent,edges[i].begin);
m = Find(parent,edges[i].end);
// n與m不等,說明此邊沒有與現有的生成樹造成環路
if (n != m) {
parent[n] = m;
printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
sum += edges[i].weight;
}
}
printf("sum = %d\n",sum);
}
複製代碼