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算法的更多相关文章

  1. 【转】最小生成树——Kruskal算法

    [转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...

  2. 模板——最小生成树kruskal算法+并查集数据结构

    并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...

  3. 数据结构之最小生成树Kruskal算法

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

  4. 并查集与最小生成树Kruskal算法

    一.什么是并查集 在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个用于次数据结构的操作: Fi ...

  5. 最小生成树——Kruskal算法理解

    背景:本文是在小甲鱼数据结构教学视频中的代码的基础上,添加详细注释而完成的.该段代码并不完整,仅摘录了核心算法部分,结合自己的思考,谈谈理解. Prim算法理解: 如图(摘录自小甲鱼教学视频中的图片) ...

  6. 最小生成树——kruskal算法

    kruskal和prim都是解决最小生成树问题,都是选取最小边,但kruskal是通过对所有边按从小到大的顺序排过一次序之后,配合并查集实现的.我们取出一条边,判断如果它的始点和终点属于同一棵树,那么 ...

  7. 最小生成树Kruskal算法

    Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1 ...

  8. 最小生成树------Kruskal算法

    Kruskal最小生成树算法的概略描述:1 T=Φ:2 while(T的边少于n-1条) {3 从E中选取一条最小成本的边(v,w):4 从E中删去(v,w):5 if((v,w)在T中不生成环) { ...

  9. 求最小生成树——Kruskal算法

    给定一个带权值的无向图,要求权值之和最小的生成树,常用的算法有Kruskal算法和Prim算法.这篇文章先介绍Kruskal算法. Kruskal算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...

随机推荐

  1. 安装聊天软件telegram-cli

    Telegram是一款加密通信的聊天软件,可以在linux,windows,android,chrome等运行.官方网址:https://telegram.org/ 它是有桌面版的,但作为一个linu ...

  2. JS和jquery加载的区别

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 常用公共DNS服务器地址

    DNS,全称Domain Name System,即域名解析系统,帮助用户在互联网上寻找路径,它在互联网的作用是把域名转换成为网络可以识别的IP地址.目前国内电信运营商通过使用DNS劫持和DNS污染的 ...

  4. 关联分析(Apriori算法)

    两个概念: 频繁项集:常出现的物品集合 关联分析:找到诸如:尿布-->啤酒的关联,反过来则是另一条 两个控制参数: 项集的支持度(support):一个项集出现的次数在所有样本中出现的比例 可信 ...

  5. 正确地使用GIT FORK

    摘自github官方网站,稍后我将抽空翻译. Fork a repo https://help.github.com/articles/fork-a-repo/ Syncing a fork http ...

  6. SDOI 2015 约束个数和

    Description: 共\(T \le 5 \times 10^4\)组询问, 每组询问给定\(n\)和\(m\), 请你求出 \[ \sum_{i = 1}^n \sum_{j = 1}^m \ ...

  7. PHP的按位运算符是什么意思

    按位运算符是什么意思? 按位运算符(Bitwise Operators)是用于对涉及单个位操作的位模式或二进制数字执行位操作的运算符. 按位运算符可以用于: 1.通信堆栈,其中标头中的各个位附加到数据 ...

  8. SecureCRT发送键盘按键对应表(转义字符)

    \r 发送回车(CR) \n 发送换行符(LF) \b 发送退格 \e 发送一个转义 \t 发送一个标签 \\ 发送一个反斜杠字符 \v 将剪贴板的内容粘贴到活动状态会话窗口 \p 暂停一秒钟

  9. 深入浅出 Cocoa 之 Core Data(3)- 使用绑定

    深入浅出 Cocoa 之 Core Data(3)- 使用绑定 罗朝辉(http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 前面讲解了 Core Data 的框架, ...

  10. Oracle Forms Execute_Query Example To Fetch The Records From Database

    Execute_Query command is used to fetch all the records for current database data block in Oracle For ...