克鲁斯卡尔(Kruskal)算法
概览
相比于普里姆算法(Prim算法),克鲁斯卡尔算法直接以边为目标去构建最小生成树。从按权值由小到大排好序的边集合{E}中逐个寻找权值最小的边来构建最小生成树,只要构建时,不会形成环路即可保证当边集合{E}中的边都被尝试了过后所形成的树为最小生成树。
定义
假设G=(V, {E})是连通网(即带权连通图),则令最小生成树的初始状态为只有N个顶点而无边的非连通图T=(V, {}),图T中每个顶点自成一个连通分量。在图G的边集{E}中选择权值最小的边e,若e依附的顶点落在T中不同的连通分量上,则将e加入到T中,否则舍去e而选择下一条权值最小的边。以此类推,直至T中所有顶点都在同一连通分量上为止。
相关概念
连通:在无向图G中,如果从顶点v到v’有路径,则称v和v’是连通的。
连通图:如果对于图G中任意两个顶点vi、vj∈E,vi和vj都是连通的,则称G是连通图。
过程简述
输入:带权连通图(网)G的边集E及顶点个数。(E已按权值的升序排序。)
初始:T=(V, {}), V是图G的顶点集合且各顶点自成一个连通分量;表示边的集合为空{}。
操作:重复以下操作,直到T中所有顶点都在同一个连通分量上。
- 依次取E中一条边e(边e必为未尝试过的边中权值最小的边。因为{E}已按权值升序排序)。
- 将e的两个顶点分别放入T的各连通分量集合V中以测试该顶点是否分别在不同连通分量中。
- 设存在一个方法/函数Find(V, vertex),从连通分量集合V的vertex顶点开始沿该连通分量查找,返回以vertex开始的连通分量的最后一个顶点(的下标)。令n=Find(V, e.begin)和m=Find(V, e.end),若n≠m则e存在于T的不同连通分量中,故将e.end加入到以e.begin开始的连通分量中去。(注:e.begin表示e的开始顶点;e.end表示e的结束顶点;虽然无向图的边不存在开始顶点或结束顶点,但是作为程序表示,也得有两个值来表示边的两个顶点。)(为什么n≠m则两个顶点分别位于不同的连通分量中?若v1、v4、v6位于同一个连通分量,v3、v7位于另一个连通分量。那么怎么表示这两个连通分量呢?可以用一个数组来表示!数组的索引本身即是顶点v的下标,而v在数组中对应的存储单元存有构成该连通分量的下一个顶点v’。用一个数组parent表示图T的V。那么parent[1]=4,parent[4]=6,parent[6]=0,0表示该连通图中已无别的顶点;parent[3]=7,parent[7]=0。对于边(1, 6)(或(6, 1)),将1带入parent数组,最终会沿着连通图找到n=6;将6带入parent数组,最终会沿着连通图找到m=6。n=m所以这两个顶点位于相同连通图中。而对于边(4, 7)(或(7, 4)),将4带入parent数组,得到n=6;将7带入parent数组,得到m=7。n≠m所以两个顶点位于不同连通图中。把点v7所处的连通图放入v1、v4、v6构成的连通图中:parent[6]=7(parent[n]=m)反过来点v4所处的连通图放入v3、v7构成的连通图中,即parent[7]=6也行,只采用两者之一即可。)
- 直到T中所有顶点都在同一连通分量上为止。(E中的每一条边都尝试一遍即可。)
输出:最小生成树。
如何实现
输入:用Edge类表示边,其中Begin/End/Weight域分别表示边的两个顶点的下标及权重。Edge数组E表示边集,N表示顶点个数。(E已按权值的升序排序。)
初始:用包含N个存储单元的数组parent表示T=(V, {})的 V,即各顶点自成的连通分量。parent数组的下标i即为顶点的下标,i处存放的值parent[i]即为连通分量中下一个顶点的下标,parent[i]=0表示该连通分量已结束。将parent的各存储单元初始化为0。
操作:重复以下操作,直到T中所有顶点都在同一个连通分量上。
- 依次取E中一条边e。
- 将e.Begin和e.End带入parent数组,找到连通分量中的最后一个顶点。n=Find(parent, e.Begin)和m=Find(parent, e.end),若n≠m则e存在于T的不同连通分量中,故将点e.End所处的连通图加入到点e.Begin所处的连通图中去,即parent[n]=m。(反过来parent[m]=n也行。)
- 直到E中的每一条边都尝试一遍即可。
输出:最小生成树。
如上面的这个图G=(V, {E}),其中V={v0, v1, v2, v3, v4, v5, v6, v7, v8},E= {(v4, v7, 7), (v2, v8, 8), (v0, v1, 10), (v0, v5, 11), (v1, v8, 12), (v3, v7, 16), (v1, v6, 16), (v5, v6, 17), (v1, v2, 18), (v6, v7, 19), (v3, v4, 20), (v3, v8, 21), (v2, v3, 22), (v3,v6, 24), (v4, v5, 26)}
用一个边集来表示该图G,得上图右边的数组。
① 输入:带权连通图G=(V, {E})的边集合及顶点数目,求图G的最小生成树。
② 初始:T={V, {}},用数组parent=int[9]来表示V,parent数组记录的是以索引i表示的顶点开始到parent[i]表示的顶点构成的连通图。例如:(parent数组本身就含有两个信息:索引和索引处的值,vertex数组是不存在的,只是为了辅助理解。)
非连通图头顶点下标vertex:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标parent:[ 0, 0, 8, 0, 7, 0, 0, 0, 0 ]
parent[2]=8,parent[8]=0即顶点v2、v8构成一个连通分量。
parent[4]=7,parent[7]=0即顶点v4、v7构成一个连通分量。
③ 操作:
1.上图中,边(4, 7, 7)权值最小,取该边为e。
2. 此时parent[4]=0,故n=4;parent[7]=0,故m=7;n≠m故parent[4]=7,将{v4}和{v7}这两个连通图合并为一个连通图。执行后parent数组如下:
非连通图头顶点下标vertex:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标parent:[ 0, 0, 0, 0, 7, 0, 0, 0, 0 ]
解释:parent[2]=0,即v2自成一个连通图。parent[4]=7,parent[7]=0即v4所在连通图中还有v7,v7接下来没有别的顶点了,即v4、v7在同一个连通图中。
3.从E中取下一条边继续上面1、2步骤的操作。
④输出:
演示过程
(4,7) = 7
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 0, 0, 0, 0, 7, 0, 0, 0, 0 ]
(2,8) = 8
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 0, 0, 8, 0, 7, 0, 0, 0, 0 ]
(0,1) = 10
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 0, 8, 0, 7, 0, 0, 0, 0 ]
(0,5) = 11
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 5, 8, 0, 7, 0, 0, 0, 0 ]
(1,8) = 12
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 5, 8, 0, 7, 8, 0, 0, 0 ]
(3,7) = 16
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 5, 8, 7, 7, 8, 0, 0, 0 ]
(1,6) = 16
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 5, 8, 7, 7, 8, 0, 0, 6 ]
(6,7) = 19
非连通图头顶点下标:[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
非连通图尾顶点下标:[ 1, 5, 8, 7, 7, 8, 7, 0, 6 ]
运行结果
(4, 7) = 7
(2, 8) = 8
(0, 1) = 10
(0, 5) = 11
(1, 8) = 12
(3, 7) = 16
(1, 6) = 16
(6, 7) = 19
算法代码
见链接:克鲁斯卡尔(Kruskal)算法(代码) - kokiafan - 博客园 (cnblogs.com)
复杂度
它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树。
参考资料:
《大话数据结构》 - 程杰 著 - 清华大学出版社 第252页
克鲁斯卡尔(Kruskal)算法的更多相关文章
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- 洛谷P3366【模板】最小生成树-克鲁斯卡尔Kruskal算法详解附赠习题
链接 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M&l ...
- 克鲁斯卡尔(Kruskal)算法
# include <stdio.h> # define MAX_VERTEXES //最大顶点数 # define MAXEDGE //边集数组最大值 # define INFINITY ...
- 图解最小生成树 - 克鲁斯卡尔(Kruskal)算法
我们在前面讲过的<克里姆算法>是以某个顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的.同样的思路,我们也可以直接就以边为目标去构建,因为权值为边上,直接找最小权值的边来构建生成树 ...
- 克鲁斯卡尔(Kruskal)算法求最小生成树
/* *Kruskal算法求MST */ #include <iostream> #include <cstdio> #include <cstring> #inc ...
- 最小生成树——Kruskal(克鲁斯卡尔)算法
[0]README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 Kruskal(克鲁斯卡尔)算法 的idea 并用 源代码加以实现: 0.2)最小生成树的基础知识,参见 ...
- 经典问题----最小生成树(kruskal克鲁斯卡尔贪心算法)
题目简述:假如有一个无向连通图,有n个顶点,有许多(带有权值即长度)边,让你用在其中选n-1条边把这n个顶点连起来,不漏掉任何一个点,然后这n-1条边的权值总和最小,就是最小生成树了,注意,不可绕成圈 ...
- 最小生成树之克鲁斯卡尔(kruskal)算法
#include <iostream> #include <string> using namespace std; typedef struct MGraph{ string ...
- 数据结构与算法——克鲁斯卡尔(Kruskal)算法
目录 应用场景-公交站问题 克鲁斯卡尔算法介绍 克鲁斯卡尔算法图解 克鲁斯卡尔算法分析 如何判断回路? 代码实现 无向图构建 克鲁斯卡尔算法实现 获取一个点的终点解释 应用场景-公交站问题 某城市新增 ...
- 图->连通性->最小生成树(克鲁斯卡尔算法)
文字描述 上一篇博客介绍了最小生成树(普里姆算法),知道了普里姆算法求最小生成树的时间复杂度为n^2, 就是说复杂度与顶点数无关,而与弧的数量没有关系: 而用克鲁斯卡尔(Kruskal)算法求最小生成 ...
随机推荐
- 手把手教你如何使用Charles抓包
一.为什么使用charles 前几天因为需要通过抓包定位问题,打开了尘封已久的fiddler,结果打开软件后什么也干不了,别说手机抓包了,打开软件什么请求也抓不到. 很多时候都是如此,如果一个方案不行 ...
- 【死磕JVM】给同事讲了一遍GC后,他要去面试,年轻人,就是容易冲动!
前言 在一个风和日丽的中午,和同事小勇一起走在公司楼下的小公园里面,看到很多的小姐姐,心想什么时候能够和这些小姐姐一起讨论人生呀,美滋滋,嘿嘿嘿. 收起你的哈喇子好不好,小勇总是在这个时候发出声音,挺 ...
- 关于在forEach中使用await的问题
先说需求,根据数组中的ID值,对每个ID发送请求,获取数据进行操作. 首先肯定考虑用forEach 或者 map对数组进行遍历,然后根据值进行操作,但是请求是个异步操作,forEach又是一个同步操作 ...
- 【C/C++】malloc和new的区别
malloc和new的区别 malloc是C语言的内存申请函数.new是C++语言的运算符.所以在.c文件中无法使用new. malloc申请空间时,传递的是size.new申请空间时,传递的是typ ...
- 基于注解的springboot+mybatis的多数据源组件的实现
通常业务开发中,我们会使用到多个数据源,比如,部分数据存在mysql实例中,部分数据是在oracle数据库中,那这时候,项目基于springboot和mybatis,其实只需要配置两个数据源即可,只需 ...
- Vue3 封装第三方组件(一)做一个合格的传声筒
各种UI库的功能都是非常强大的,尤其对于我这种不会 css 的人来说,就更是帮了大忙了. 只是嘛,如果再封装一下的话,那么用起来就会更方便了. 那么如何封装呢? 封装三要素 -- 属性.插槽.事件.方 ...
- 2021年HW0day-奇安信 网康下一代防火墙 RCE漏洞细节
漏洞信息: 漏洞名称:奇安信 网康下一代防火墙 RCE漏洞. 漏洞性质:远程命令执行 漏洞利用特点:命令执行之后没有回显 利用方式:防火墙使用linux进行开发的,可以使用echo xxx >1 ...
- 2. linux下如何上传和下载文件
一. 安装工具包 yum install -y lrzsz lrzsz是一个unix通信套件提供的X,Y,和ZModem文件传输协议,可以用在windows与linux 系统之间的文件传输,体积小速度 ...
- (十三)Docker容器进入的4种方式
简介 在使用Docker创建了容器之后,大家比较关心的就是如何进入该容器了,其实进入Docker容器有好几多种方式,这里我们就讲一下常用的几种进入Docker容器的方法. 进入Docker容器比较常见 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...