数据结构:最小生成树--Kruskal算法
Kruskal算法
Kruskal算法
求解最小生成树的还有一种常见算法是Kruskal算法。它比Prim算法更直观。从直观上看,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<iostream>
#include<algorithm>
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;
}
执行
转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38414683
若有所帮助,顶一个哦。
专栏文件夹:
数据结构:最小生成树--Kruskal算法的更多相关文章
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- 数据结构之最小生成树Kruskal算法
1. 克鲁斯卡算法介绍 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路. 具体做法:首先构造一个 ...
- 并查集与最小生成树Kruskal算法
一.什么是并查集 在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个用于次数据结构的操作: Fi ...
- 最小生成树——Kruskal算法理解
背景:本文是在小甲鱼数据结构教学视频中的代码的基础上,添加详细注释而完成的.该段代码并不完整,仅摘录了核心算法部分,结合自己的思考,谈谈理解. Prim算法理解: 如图(摘录自小甲鱼教学视频中的图片) ...
- 最小生成树——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算法
给定一个带权值的无向图,要求权值之和最小的生成树,常用的算法有Kruskal算法和Prim算法.这篇文章先介绍Kruskal算法. Kruskal算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...
随机推荐
- C#反射(Reflection)详解
1. 什么是反射2. 命名空间与装配件的关系3. 运行期得到类型信息有什么用4. 如何使用反射获取类型5. 如何根据类型来动态创建对象6. 如何获取方法以及动态调用方法7. 动态创建委托 1.什么是反 ...
- C# 数组与 list 互相转换案例
在项目中用到了 随手分享下 记得点赞呦! 1,从System.String[]转到List<System.String>System.String[] str={"str&quo ...
- 洛谷 P1618 三连击(升级版)【DFS/next_permutation()/技巧性枚举/sprintf】
[链接]:https://www.luogu.org/problemnew/show/P1618 题目描述 将1,2,…,9共9个数分成三组,分别组成三个三位数,且使这三个三位数的比例是A:B:C,试 ...
- 使用putty通过证书登录Linux
refer to: https://www.aliyun.com/jiaocheng/200196.html
- usaco-Money Systems
题意: 给出几种硬币,求可用这几种硬币组合出价值为n的方案数.分析: 设dp[i]表示组合出价值i的方案数,则,dp[i]=∑dp[i-val[j]]. #include <iostream&g ...
- Your build settings specify a provisioning profile with the UUID, no provisioning profile was
http://blog.csdn.net/rbyyyblog/article/details/12220875 在Archive项目时,出现了“Your build settings specify ...
- EasyMvc入门教程-图形控件说明(21)线形图+柱状图+饼形图
本章将介绍一些基本但常用的图形:线型图,柱状图和饼形图. 以上三种图形对于的数据都是键值对数组,请参考第一个例子: @{ var data = new List<LineItem>(); ...
- Elite Container DELPHI下的一个轻量级IoC对象容器
一.简介: Elite Container是DELPHI下的一个轻量级IoC对象容器(IoC:Inverse of Control,反转控制).它是参考了Java中的Spring框架(主要是配置文件的 ...
- NVIDIA® Quadro® 四路缓冲 3D立体方案
http://www.nvidia.cn/object/quadro_pro_graphics_boards_cn.html NVIDIA® Quadro® 专业显卡让地球学家以及时装设计师等许多专业 ...
- Vbs脚本经典教材
转载:http://www.cnblogs.com/BeyondTechnology/archive/2011/01/10/1932440.html Vbs脚本经典教材(最全的资料还是MSDN) —为 ...