博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构:最小生成树--Kruskal算法
阅读量:6375 次
发布时间:2019-06-23

本文共 3277 字,大约阅读时间需要 10 分钟。

                           Kruskal算法

Kruskal算法

    求解最小生成树的还有一种常见算法是Kruskal算法。它比更直观。从直观上看,Kruskal算法的做法是:每次都从剩余边中选取权值最小的,当然,这条边不能使已有的边产生回路。

手动求解会发现Kruskal算法异常简单,以下是一个样例

先对边的权值排个序:1(0,1) 2(2,6) 4(1,3) 6(1,2) 8(3,6) 10(5,6) 12(3,5) 15(4,5) 20(0,1)

首选边1(0,1)、2(2,6)、4(1,3)、6(1,2),此时的图是这样

显然,若选取边8(3,6)会出现环,则必须抛弃8(3,6),选择下一条10(5,6)没有问题。此时图变成这样

显然,12(3,5)相同不可取,选取15(4,5),边数已达到要求,算法结束。终于的图是这种

算法逻辑人非常easy理解。但用代码推断当前边是否会引起环的出现。则非常棘手。

算法说明

    为了推断环的出现,我们换个角度来理解Kruskal算法的做法:初始时,把图中的n个顶点看成是独立的n个连通分量,从树的角度看,也是n个根节点。我们选边的标准是这种:若边上的两个顶点从属于两个不同的连通分量。则此边可取,否则考察下一条权值最小的边。

    于是问题又来了,怎样推断两个顶点是否属于同一个连通分量呢?这个能够參照并查集的做法解决。它的思路是:假设两个顶点的根节点是一样的,则显然是属于同一个连通分量。

这也相同暗示着:在增加新边时,要更新父节点。

详细细节看代码:

代码

#include
#include
using namespace std;#define MAXWEIGHT 100/*全局变量numV顶点数numE边数*/int numV, numE;//边typedef struct edge_tag{ int tail; int head; int weight;}Edge;//检測边bool checkEdge(int tail, int head, int weight){ if (tail == head || tail < 0 || tail >= numV || head < 0 || head >= numV || weight <= 0 || weight >= MAXWEIGHT) return false; return true;}//输入边void inputEdge(Edge *edge, int numE){ int i, tail, head, weight; cout << "输入边的起点、终点和权值" << endl; i = 0; while (i < numE) { cin >> tail >> head >> weight; while (!checkEdge(tail, head, weight)) { cout << "输入错误!又一次输入" << endl; cin >> tail >> head >> weight; } edge[i].tail = tail; edge[i].head = head; edge[i].weight = weight; i++; }}int cmp(const void *edge1, const void *edge2){ return ((Edge*)edge1)->weight - ((Edge*)edge2)->weight;}//并查集的常见操作/*压缩查找查找child的根节点*/int Find(int child, int *parent){ if (parent[child] == child) return child; parent[child] = Find(parent[child], parent); //压缩路径 return parent[child];}//合并bool Union(Edge *e, int *parent, int *childs){ //处于同一个棵树中。则不能合并。否则会出现环 int root1, root2; root1 = Find(e->tail, parent); root2 = Find(e->head, parent); if (root1 != root2) { //把小树合并到大树根下 if (childs[root1] > childs[root2]) { parent[root2] = root1; childs[root1] += childs[root2] + 1; } else { parent[root1] = root2; childs[root2] += childs[root2] + 1; } return true; } return false;}/*Kruskal算法求最小生成树*/void Kruskal(int numV, int numE){ //边的集合 Edge *edge = new Edge[numE]; inputEdge(edge, numE); /* parent[i]是顶点i的父顶点 childs[i]是顶点i的孩子数 child的复数是children,这里的childs是杜撰的 */ int *parent = new int[numV]; int *childs = new int[numV]; //初始化 for (int i = 0; i < numV; i++) { /* 初始时。每个顶点都是根。且无孩子 把每个顶点的的父节点设置为自身下标,也是标明类别 */ parent[i] = i; childs[i] = 0; } //对边按权值进行从小到大排序 qsort(edge, numE, sizeof(Edge), cmp); int i, count; i = count = 0; cout << "最小生成树的边..." << endl; while (i < numE) { if (Union(&edge[i], parent, childs)) { cout << edge[i].tail << "---" << edge[i].head << endl; count++; } if (count == numV - 1) //边数达到要求 break; i++; } if (count != numV - 1) cout << "此图为非连通图!

无法构成最小生成树。" << endl; delete[]edge; delete[]parent; delete[]childs; } //检測顶点数和边数 bool checkVE(int numV, int numE) { if (numV <= 0 || numE <= 0 || numE > numV*(numV - 1) / 2) return false; return true; } int main() { cout << "******Kruskal***by David***" << endl; cout << "输入顶点数、边数 "; cin >> numV >> numE; while (!checkVE(numV, numE)) { cout << "输入数据有问题!又一次输入 "; cin >> numV >> numE; } cout << endl << "Kruskal..." << endl; Kruskal(numV, numE); system("pause"); return 0; }

执行

转载请注明出处,本文地址:

若有所帮助,顶一个哦。

专栏文件夹:

  •  
你可能感兴趣的文章
IOS-UI基础-按钮
查看>>
删除/添加/调用WordPress用户个人资料的联系信息
查看>>
POJ 3744 Scout YYF I 矩阵快速幂
查看>>
在linux下执行依赖多个jar的类的方法
查看>>
****** 二十五 ******、软设笔记【数据库】-数据库语言-数据定义、数据查询
查看>>
day7面向对象--反射
查看>>
文件打开方式
查看>>
ERROR 2002
查看>>
NET多线程探索-NET线程基础知识点
查看>>
Oracle 11g R2 新特性
查看>>
微信小程序新手知识
查看>>
java中数据流的简单介绍
查看>>
根据物流号查看物流信息
查看>>
jsp设置MIME类型
查看>>
python模拟自动登录网站(urllib2)
查看>>
Java 对文件的操作
查看>>
洛谷 题解 P3627 【[APIO2009]抢掠计划】
查看>>
springboot传入json和文件_SpringBoot系列教程22-整合SpringMVC之HttpMessageConverters
查看>>
不礼让行人怎么抓拍的_张家川公安交警持续曝光机动车不礼让行人【第24期】...
查看>>
用pythonturtle写名字_去年爆款新生儿名字,家长自以为起的不错,却有“棺材”的意思...
查看>>