数据结构:最小生成树--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算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...
随机推荐
- interview ms1 N_Dorm
判断是否为n回文,比如 a b a 是1 回文, abcdab是2回文. 输入: abcabc|3 这种格式,输出true or false #include <iostream> #in ...
- 在DB2中使用EXPORT实现将数据导出文本文件
EXPORT TO "D:/test.txt" OF DEL SELECT loginname,password FROM cm_staff where loginname = ' ...
- HTML5-contentEditable属性规定是否可编辑元素的内容
contentEditable='true' :可以编辑 contentEditable='false' :不可以编辑
- (4)python tkinter-布局
包装布局pack() 目前对它的感觉是,当一个窗体的对象都设置完属性后,最后用它来绑定到窗体上.之后就不能再设置属性了 名称 描述 取值范围 expand 当值为“yes”时,side选项无效.组件显 ...
- Codeforces 371B Fox Dividing Cheese(简单数论)
题目链接 Fox Dividing Cheese 思路:求出两个数a和b的最大公约数g,然后求出a/g,b/g,分别记为c和d. 然后考虑c和d,若c或d中存在不为2,3,5的质因子,则直接输出-1( ...
- luogu P1260 工程规划(luogu wa)don't know way
题目描述 造一幢大楼是一项艰巨的工程,它是由n个子任务构成的,给它们分别编号1,2,…,n(5≤n≤1000).由于对一些任务的起始条件有着严格的限制,所以每个任务的起始时间T1,T2,…,Tn并不是 ...
- Centos7下实现多虚拟机互信
假设CentOS 7三台虚拟机A(192.168.111.10).B(192.168.111.11).C(192.168.111.12),需要保证三台虚拟机之间网络的连通性. 操作步骤: 一.在A机上 ...
- 2016北京集训测试赛(十一)Problem C: 树链问题
Solution 智障暴力题, 每个点维护一下子树信息, 树剖就好了. 我居然还傻了写了一发毛毛虫... #include <cstdio> #include <cctype> ...
- oracle小知识点16-诊断事件diagnostic events
http://blog.itpub.net/28539951/viewspace-1983919/
- weblogic的集群与配置图文
一.Weblogic的集群 还记得我们在第五天教程中讲到的关于Tomcat的集群吗? 两个tomcat做node即tomcat1, tomcat2,使用Apache HttpServer做请求派发 ...