现在我们来换一种思考方式,普里姆(Prim)算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的。这就像是我们如果去参观某个展会,例如世博会,你从一个入口进去,然后找你所在位置周边的场馆中你最感兴趣的场馆观光,看完后再用同样的办法看下一个。可我们为什么不事先计划好,进园后直接到你最想去的场馆观看呢?

同样的思路,我们也可以直接就以边为目标去构建,因为权值是在边上,直接去找最小权值的边来构建生成树也是很自然的想法,只不过构建时要考虑是否会形成环路而已。此时我们就用到了图的存储结构中的边集数组结构。以下是edge边集数组结构的定义代码:

/*边集数组Edge结构*/
typedef struct
{int begin;int end;int weight;
}Edge;

边集数组是由二维数组构成。这个边数组每个数据元素由一条边的起点下标(begin)、终点下标(end)和权(weight)组成,如下图所示。

其中begin是存储起点下标,end是存储终点下标,weight是存储权值。

下图为某个带权无向图以及它的边集数组

可以发现这个边集数组是按weight(权值)来排序的。

具体的实现方式如下:

#include<iostream>
#include<vector>
#include<queue>
using namespace std;#define MAXVEX 100//最大顶点数
typedef char VertexType;//顶点类型
typedef int EdgeType;//边上的权值类型
typedef struct
{VertexType vexs[MAXVEX];//顶点表EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵int numVertexte;//当前顶点数int numEdges;//当前边数
}MGraph;/*边集数组Edge结构*/
typedef struct
{int begin;int end;int weight;
}Edge;void MiniSpanTree_Kruskal(MGraph G)
{vector<Edge> edges(G.numVertexte);//定义边集数组vector<int> parents(G.numVertexte);//该数组用来判断边与边是否形成环路/*初始化边集数组*/for (int i = 0; i < G.numVertexte; ++i){for (int j = 0; j < G.numVertexte; ++j){if (G.arc[i][j] != 0 && G.arc[i][j] != INT_MAX){edges.push_back({ i,j,G.arc[i][j] });G.arc[j][i] = INT_MAX;}}}sort(edges.begin(), edges.end(), [&](const Edge& a, const Edge& b){return a.weight <= b.weight;});//让边集数组按照权值来从小到大排序for (int i = 0; i < G.numVertexte; ++i){parents[i] = 0;}for (int i = 0; i < G.numVertexte; ++i)//循环每一条边{int n = Find(parents, edges[i].begin);int m = Find(parents, edges[i].end);if (m != n)//如果m != n,说明此边没有和现有生成树形成环路{parents[n] = m;cout << edges[i].begin << edges[i].end << edges[i].weight << endl;}}
}int Find(vector<int>& parents, int f)//寻找连线顶点的尾部下标
{while (parents[f] > 0){f = parents[f];}return f;
}

最终的结果如下图所示:

现在我们着重来看一下数组parents的含义:

  1. 当i = 0时,计算得知n = 4,m = 7,且m != n,那么我们将(v4,v7)纳入最小生成树中,此时的parents数组为{0,0,0,0,7,0,0,0,0}。
  2. 当i = 1时,计算得知n = 2,m = 8,且m != n,那么我们将(v2,v8)纳入最小生成树中,此时的parents数组为{0,0,8,0,7,0,0,0,0}。
  3. 当i = 2时,计算得知n = 0,m = 1,且m != n,那么我们将(v0,v1)纳入最小生成树中,此时的parents数组为{1,0,8,0,7,0,0,0,0}。
  4. 当i = 3时,计算得知n = 0,m = 5,且m != n,那么我们将(v0,v5)纳入最小生成树中,但我们发现此时已经有了parents[0] = 1,即v0->v1了,那么在想要从v0->v5,就要途径v1了,即变为了v0->v1->v5,此时的parents数组为{1,5,8,0,7,0,0,0,0}。
  5. 当i = 4时,计算得知n = 1,m = 8,且m != n,那么我们将(v1,v8)纳入最小生成树中,但我们发现此时已经有了parents[1] = 5,即v1->v5了,那么在想要从v1->v8,就要途径v5了,即变为了v1->v5->v8,此时的parents数组为{1,5,8,0,7,8,0,0,0}。
  6. 当i = 5时,计算得知n = 3,m = 7,且m != n,那么我们将(v3,v7)纳入最小生成树中,此时的parents数组为{1,5,8,7,7,8,0,0,0}
  7. 当i = 6时,计算得知n = 1,m = 6,且m != n,那么我们将(v1,v6)纳入最小生成树中,但我们发现此时已经有了parents[1] = 5,即v1->v5了,那么在想要从v1->v6,就要途径v5和v8了,即变为了v1->v5->v8->v6,此时的parents数组为{1,5,8,7,7,8,0,0,6}。
  8. 当i=7时,会得到m = n的结果,即会形成环,所以跳过这次循环。
  9. 当i=8时,会得到m = n的结果,即会形成环,所以跳过这次循环。
  10. 当i = 9时,计算得知n = 6,m = 7,且m != n,那么我们将(v6,v7)纳入最小生成树中,此时的parents数组为{1,5,8,7,7,8,7,0,6}。
  11. 此后边的循环均造成环路,我们不再讨论。

如果不考虑初始化边集数组,和将边集数组按照权值排序的时间复杂度,那么此算法的Find函数由边数e决定,时间复杂度为O(log e),而外面有一个for循环e次。所以克鲁斯卡尔算法的时间复杂度为O(elog e)。

克鲁斯卡尔算法主要是针对边来展开,边数少时效率会非常高,所以对于稀疏图有很大的优势;而普里姆算法对于稠密图,即边数非常多的情况会更好一些。

五、最小生成树——克鲁斯卡尔(Kruskal)算法相关推荐

  1. 7、最小生成树,克鲁斯卡尔(Kruskal)算法

    1)算法的基本思想: 前面我们学习过Prim算法,他是一种以某个节点出发,按权值递增的次序选择合适的边来构造最小生成树的方法,他的时间复杂度为O(n2),与顶点有关,而与边无边,所以适合求边稠密的图的 ...

  2. 克鲁斯卡尔算法c语言,最小生成树-克鲁斯卡尔(Kruskal)算法

    1. 克鲁斯卡尔算法简介 克鲁斯卡尔算法是一种用来寻找最小生成树的算法(用来求加权连通图的最小生成树的算法).在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边. 而具体 ...

  3. 数据结构与算法(7-3)最小生成树(普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法)

    目录 一.最小生成树简介 二.普里姆算法(Prim) 1.原理 2.存储 2-1.图顶点和权: 2-3. 最小生成树: 3.Prim()函数 3-1.新顶点入树 3-2.保留最小权 3-3. 找到最小 ...

  4. 对下图所示的连通网络G,用克鲁斯卡尔(Kruskal)算法求G的最小生成树T,请写出在算法执行过程中,依次加入T的边集TE中的边。说明该算法的基本思想及贪心策略,并简要分析算法的时间复杂度

    对下图所示的连通网络G,用克鲁斯卡尔(Kruskal)算法求G的最小生成树T,请写出在算法执行过程中,依次加入T的边集TE中的 边.说明该算法的基本思想及贪心策略,并简要分析算法的时间复杂度

  5. 算法:通过克鲁斯卡尔(Kruskal)算法,求出图的最小生成树

    之前我给大家分享过用普利姆(Prim)算法来求出图的最小生成树(点我去看看),今天我再给大家分享一个也是求图的最小生成树的克鲁斯卡尔(Kruskal)算法 克鲁斯卡尔(Kruskal)算法,就相当于先 ...

  6. Java实现之克鲁斯卡尔(Kruskal)算法

    一.问题引入 1.问题引入 1)某城市新增7个站点(A,B,C,D,E,F,G),现在需要修路把7个站点连通 2)各个站点的距离用边线表示(权),比如A-B距离12公里 3)问:如何修路保证各个站点都 ...

  7. 【数据结构与算法】克鲁斯卡尔(Kruskal)算法

    一,应用场景 公交站问题 1)某城市新增7个站点(A,B,C,D,E,F,G),现在需要修路把7个站点连通 2)各个站点的距离用边线表示(权),比如 A - B距离12公里 3)问:如何修路保证各个站 ...

  8. 【算法】克鲁斯卡尔 (Kruskal) 算法

    目录 1.概述 2.代码实现 2.1.并查集 2.2.邻接矩阵存储图 2.3.邻接表存储图 2.4.测试代码 3.应用 本文参考: <数据结构教程>第 5 版 李春葆 主编 1.概述 (1 ...

  9. 算法之克鲁斯卡尔(Kruskal)算法

    克鲁斯卡尔(Kruskal)算法 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路 具体做法:首先 ...

  10. 普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

    图是一种基础又重要的数据结构,图的生成树是图的一个极小连通子图.最小生成树是无向连通网的所有生成树中边的权值之和最小的一棵生成树.求图的最小生成树可以牵引出很多经典的题目,例如在N个城市之间建立通讯网 ...

最新文章

  1. Python学习全家桶,Python初学者十一个热门问题
  2. testng执行参数_TestNG中注解使用 笔记
  3. input长度随输入内容动态变化 input光标定位在最右侧
  4. eclipse 安装 lombok插件
  5. oracle 设置 shmmax,安装ORACLE时在Linux上设置内核参数的含义
  6. 移动端API接口优化的术和结果
  7. docx文档怎么排列图片_PDF怎么转Word?这几款软件满足你的要求
  8. 【国产MCU移植】看看有没有你需要的,一起来查漏补缺吧!(附已报名的硬件)...
  9. QuantLib教程(三)BS模型、二叉树模型与欧式期权定价
  10. Java---XML的解析(1)-DOM解析
  11. %E6%9D%8E%E9%9B%B7是什么编码
  12. 高德地图两种引入方式
  13. 如何去除图片背景颜色?怎样将背景色变透明?
  14. python按概率生成随机数
  15. 重置域管理员密码_如何在Server 2008 R2上重置忘记的域管理员密码
  16. 【第二季】Arcgis地图制图基础|(四)地图文字标注
  17. uniapp 腾讯云活体人脸核身(超详细)
  18. c++2048小游戏编写
  19. Linux定时任务与开机自启动脚本(cron与crontab)
  20. 介绍当前计算机软件应用发展状况,简要介绍我国当前税收征管软件的应用状况...

热门文章

  1. 微信公众号新增永久性素材
  2. 能通话的Apple Watch,为什么只有联通可以首发?
  3. 11G RAC 私网直连CRS-5818 CRS-2757
  4. 户外直播平台有哪些?你会选哪一个呢?
  5. 游戏开发—英雄类属性
  6. 如何用Free Download Manager下载百度网盘
  7. mac如何恢复删除的文件?
  8. linux编辑文件后怎么保存不了,linux编辑文件后如何保存并退出
  9. 文件怎么转换成pdf格式?只需这个一键转换神器
  10. club portal.php,任性品吸Cohiba Club(高希霸 俱乐部)