数据结构与算法 -- 图的应用之最小生成树问题
前言
前面对 图的存储 和 **图的遍历(广度优先/深度优先)**做了简单的学习和了解,本篇文章,学习一下最小生成树的问题,以及对应解决这个问题的两种算法 普里姆算法 和 克鲁斯卡尔算法
1.最小生成树问题
首先看下面一道面试题:
假设目前有
N
个顶点,每个顶点连接的路径不一样,设计一个算法,快速查找出能覆盖所有顶点的路径。
其实这个问题并不是求解两点之间的最短路径,而是设计一个路线,能覆盖所有的顶点。
如下连通图:
那么覆盖所有顶点的路径有一下几种
-
方法一
V0 ——> V5 ——> V4 --> V3 --> V2 -->V1 -->V8 --> V6 -->V7
权重:11 + 26 + 20 + 22 + 18 + 21 + 24 + 19 = 161
-
方案二
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
条边,连接所有顶点,而且权重的和最小的路径。
2.最小生成树求解(普里姆(Prim)算法)
普里姆算法思路:
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
对应V2、V6、V8
,是针对V1
相关的顶点,1
是因为k = 1
,表示与V1
相连的顶点是V2、V6、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
相连的顶点V2、V6、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