最小生成树——Kruskal算法理解
背景:本文是在小甲鱼数据结构教学视频中的代码的基础上,添加详细注释而完成的。该段代码并不完整,仅摘录了核心算法部分,结合自己的思考,谈谈理解。
Prim算法理解:
如图(摘录自小甲鱼教学视频中的图片),是一个带有权值的连通网:

根据上图可以列写出该连通网的邻接表,为了方便直观的理解:(邻接表初始化需按照权值增序排列)
| edges数组 | begin | end | weight |
| edge0 | 4 | 7 | 7 |
| edge1 | 2 | 8 | 8 |
| edge2 | 0 | 1 | 10 |
| edge3 | 0 | 5 | 11 |
| edge4 | 1 | 8 | 12 |
| edge5 | 3 | 7 | 16 |
| edge6 | 1 | 6 | 16 |
| edge7 | 5 | 6 | 17 |
| edge8 | 1 | 2 | 18 |
| edge9 | 6 | 7 | 19 |
| edge10 | 3 | 4 | 20 |
| edge11 | 3 | 8 | 21 |
| edge12 | 2 | 3 | 22 |
| edge13 | 3 | 6 | 24 |
| edge14 | 4 | 5 | 26 |
以下简单描述算法运行的流程(仅描述前几次循环,旨在理解算法工作过程),主要记录和对比parent数组和最小生成树的的逐渐生成的过程:
Kruskal算法核心思想:尽可能只选用权值最小的边连成树,即为最小生成树,因此以权值升序顺序对各边进行循环判断。最理想的情况就是权值最小的几条边恰好连成最小生成树,但是实际过程中很可能会在连接过程中形成环路(树中不允许有环路),因此一个重要的步骤就是判断当前边的加入是否会导致生成树中出现环路(即代码中parent数组的作用和m!=n判断条件的来历)。
Kruskal算法和Prim算法的主要区别就是Prim算法是以定点为单位,Kruskal算法是以边为单位。因此这里所说的(第一次、第二次)循环过程实际是对于上面的邻接表中每一条进行循环判断(是否需要添加到最小生成树中)。
在理解以下过程的时候,先浏览几遍最下方的代码,逐步对比,最容易理解。
以下对于边以及循环次数的命名以0开始,为了和上面的邻接表相对应,以防止混淆。
0、第0次(edge0)
第0次循环,对第0条边进行判断:
| edges数组 | begin | end | weight |
| edge0 | 4 | 7 | 7 |
执行Find函数,得到的n = 4,m = 7。
m != n 表示不存在环路(这里不理解可以继续看以下的几个循环),则在parent数组中记录这条边带来的连接关系(parent[4] = 7)。
| parent数组 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | n | m |
| 初始化 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \ | \ |
| 第0次 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 4 | 7 |
生成树:

1、第1次
第1次循环,对第1条边进行判断:
| edges数组 | begin | end | weight |
| edge1 | 2 | 8 | 8 |
执行Find函数,得到的n = 2,m = 8。
m != n 表示不存在环路,则记录连接关系(parent[2] = 8)。
| parent数组 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | n | m |
| 第0次 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 4 | 7 |
| 第1次 | 0 | 0 | 8 | 0 | 7 | 0 | 0 | 0 | 0 | 2 | 8 |
生成树:

此处省略几次循环......只叙述比较有特点的循环。
4、第4次
第4次循环,对第4条边进行判断:
| edges数组 | begin | end | weight |
| edge4 | 1 | 8 | 12 |
执行Find函数(参考下面第3次迭代后的parent数组),parent[1] = 5; parent[5] = 8; 得到的n = 5。parent[8] = 0; 得到m = 8。
m != n 表示不存在环路,则记录连接关系(parent[5] = 8)。
| parent数组 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | n | m |
| 第3次 | 1 | 5 | 8 | 0 | 7 | 0 | 0 | 0 | 0 | ||
| 第4次 | 1 | 5 | 8 | 0 | 7 | 8 | 0 | 0 | 0 | 5 | 8 |
生成树:
这里要注意:parent数组中的对应关系并不表示生成树中的边的关系,比如之前的循环中会在parent数组中添加如下内容:parent[1] = 5; 它表示的是1和5定点在同一个生成树中,之间存在连接关系,但并不表示存在V1->V5这样的一条边。(我自己理解的是,这个关系实际是由V0->V5的这样的一条边的加入而生成的,但是parent[0]已经被幅值为1,即表示与V1存在连接关系,故借用V1来表示出这个关系,自己的一种理解,可能错误,不要干扰思维)。

此处再次省略几次循环......只叙述一次比较特殊的循环(m==n的情况)。
7、第7次
第7次循环,对第7条边进行判断:
| edges数组 | begin | end | weight |
| edge7 | 5 | 6 | 17 |
执行Find函数(参考下面第6次迭代后的parent数组),parent[5] =85; parent[8] = 6; 得到的n = 6。parent[6] = 0; 得到m = 6。
m == n 表示存在环路,则忽略这条边(不添加到最小生成树中)。
| parent数组 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | n | m |
| 第6次 | 1 | 5 | 8 | 7 | 7 | 8 | 0 | 0 | 6 | ||
| 第7次 | 1 | 5 | 8 | 0 | 7 | 8 | 0 | 0 | 6 | 6 | 6 |
在实际的生成树可以直观的看出V5和V6之间的连线不应该加入(会形成环路),如下图为进行第7次循环之前的生成树情况:

可见,V5->V6边的加入将导致最小生成树中出现环路,因此舍弃。
......
如此对所有边进行循环,判断是否应该加入最小生成树中,直至循环结束,则生成树完成。
代码如下:(仅Kruskal算法的两个核心函数)
int Find(int *parent,int f)
{
/* parent该数组元素>0表示已完成的生成树中存在与该顶点有连接关系的顶点 */
while(parent[f] > 0)
{
/* 则迭代寻找与该点存在连接关系的结束顶点(当前所在树的结束顶点) */
f = parent[f];
}
return f;
}
void MiniSpanTree_Kruskal(MGraph G)
{
int i,n,m;
/* 边数组:应按照边的权值升序进行初始化 */
Edge edges[MAXEDGE];
/* parent数组用来存放顶点之间的连接关系 以判断是否存在环路 */
int parent[MAXVEX];
/* parent数组初始化 */
for(i=0;i<G.numVertexes;i++)
{
parent[i] = 0;
}
for(i=0;i<G.numVertexes;i++)
{
n = Find(parent,edges[i].begin);
m = Find(parent,edges[i].end);
/* 若n == m则表示形成环路 */
if(n != m)
{
/* 若未形成环路 */
/* 将该边添加到生成树中(此处即打印) */
/* 将由该边引起的连接关系保存到parent数组中(注意这里不是简单的将边保存到parent数组中 而是保存了一种连接关系) 表示该顶点已经在生成树中 */
/* 存放方式:parent[p] = q表示:从顶点p到顶点q存在通路(即顶点p和顶点q在同一个生成树中) */
parent[n] = m;
printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
——cloud over sky
——2020/3/12
最小生成树——Kruskal算法理解的更多相关文章
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...
- 求最小生成树——Kruskal算法
给定一个带权值的无向图,要求权值之和最小的生成树,常用的算法有Kruskal算法和Prim算法.这篇文章先介绍Kruskal算法. Kruskal算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...
- 数据结构:最小生成树--Kruskal算法
Kruskal算法 Kruskal算法 求解最小生成树的还有一种常见算法是Kruskal算法.它比Prim算法更直观.从直观上看,Kruskal算法的做法是:每次都从剩余边中选取权值最小的,当然,这条 ...
- 【一个蒟蒻的挣扎】最小生成树—Kruskal算法
济南集训第五天的东西,这篇可能有点讲不明白提前抱歉(我把笔记忘到别的地方了 最小生成树 概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的 ...
- 最小生成树kruskal算法、
克鲁斯卡尔(kruskal) //kruskal算法生成最小生成树. //对边集数组Edge结构的定义 typedef struct { int begin; int end; int weight; ...
- 最小生成树——kruskal算法
kruskal和prim都是解决最小生成树问题,都是选取最小边,但kruskal是通过对所有边按从小到大的顺序排过一次序之后,配合并查集实现的.我们取出一条边,判断如果它的始点和终点属于同一棵树,那么 ...
- 最小生成树Kruskal算法
Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1 ...
- 最小生成树------Kruskal算法
Kruskal最小生成树算法的概略描述:1 T=Φ:2 while(T的边少于n-1条) {3 从E中选取一条最小成本的边(v,w):4 从E中删去(v,w):5 if((v,w)在T中不生成环) { ...
- 最小生成树 kruskal算法&prim算法
(先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...
随机推荐
- vue添加,删除内容
vue 提交添加内容,点击删除内容 1 html <input v-model="inputValue" /> <button @click="hand ...
- tomcat多个springboot项目启动失败
多个springboot项目打包成war包并放到tomcat下运行时出错了错误信息: Caused by: org.springframework.jmx.export.UnableToRegiste ...
- 数据可视化:使用python代码实现可视数据随机漫步图
#2020/4/5 ,是开博的第一天,希望和大家相互交流学习,很开森,哈哈~ #像个傻子哟~ #好,我们进入正题, #实现功能:利用python实现数据随机漫步,漫步点数据可视化 #什么是 ...
- tomcat日志清理
删除指定IP的日志后,删除自身 import os import time import sys ip="127.0.0.1" logpath="/var/lib/tom ...
- saltstack升级
1.背景 saltstack出现安全漏洞,5.1前后爆出很多设备已经变成矿机. 2.处理方法 升级到最新版本salt 3.官方升级方法 yum install https://repo.saltsta ...
- 使用Proteus模拟操作HDG12864F-1液晶屏
在Proteus中模拟了89C52操作HDG12864F-1液晶屏,原理图如下: 一.HDG12864F-1官网信息 该液晶屏是Hantronix的产品,官网上搜索出这个型号是系列型号中的一种,各种型 ...
- python地图投影转换
一.投影包osr与proj4的使用 1.osr投影转换示例 from osgeo import osr,ogr#定义投影#wgs84source=osr.SpatialReference()sourc ...
- 解密C语言编译背后的过程
我们大部分程序员可能都是从C语言学起的,写过几万行.几十万行.甚至上百万行的代码,但是大家是否都清楚C语言编译的完整过程呢,如果不清楚的话,我今天就带着大家一起来做个解密吧. C语言相对于汇编语言是一 ...
- 【Hadoop离线基础总结】Hive的安装部署以及使用方式
Hive的安装部署以及使用方式 安装部署 Derby版hive直接使用 cd /export/softwares 将上传的hive软件包解压:tar -zxvf hive-1.1.0-cdh5.14. ...
- CF#633 C. Powered Addition 思维
Powered Addition 题意 给出n个数字,现在你可以在第x秒,选择任意数量的下标,让这些位置上的数加上\(2^{x-1}\),问最快需要几秒使得数列变成一个非递减的序列. 思路 让求x的最 ...