【算法与数据结构】并查集 Disjoint Set
并查集(Disjoint Set)用来判断已有的数据是否构成环。
在构造图的最小生成树(Minimum Spanning Tree)时,如果采用 Kruskal 算法,每次添加最短路径前,需要先用并查集来判断一下这个路径是否会构成环。
思路
遍历图的每一条边,按照下面的原则将对应的两个顶点添加到集合中:
- 如果两个顶点都不属于任一集合,则创建新的集合,并将这两个顶点放入
- 如果两个顶点都已经属于某个集合,则已经构成环,退出
- 如果有一个顶点已经属于某个集合,则将另一个顶点也加入这个集合
为了代码上的统一性,可以在开始前,把所有顶点都看成只有一个元素的集合,然后就是不停的合并集合。
集合可以用树的双亲表示法来表示,只需要额外创建一个数组即可。为了简化合并操作,可以每次都只操作两颗树的根结点。
int parent[n];
// 查找树的根结点
int findRoot(int parent[], int key) {
int root = key;
while (parent[root] != -1) {
root = parent[root];
}
return root;
}
// 合并树
int unionVertex(int parent[], int x, int y) {
int lRoot = findRoot(parent, x);
int rRoot = findRoot(parent, y);
// 两个结点的根结点为同一个,则这两个结点属于同一棵树
if (lRoot == rRoot) {
return 0;
}
// 否则,合并树,这里直接把左树作为右树的子树,可能会导致不平衡
parent[lRoot] = rRoot;
}
代码
为了在每次合并时,尽可能保证树的平衡,再创建一个数组保存树的高度,合并时将高度低的树作为子树即可。
#include <stdio.h>
void init(int parent[], int height[], int count) {
int i;
for (i = 0; i < count; i++) {
parent[i] = -1;
height[i] = 0;
}
}
int findRoot(int parent[], int key) {
int root = key;
while (parent[root] != -1) {
root = parent[root];
}
return root;
}
int unionVertex(int parent[], int height[], int x, int y) {
int lRoot = findRoot(parent, x);
int rRoot = findRoot(parent, y);
if (lRoot == rRoot) {
return 0;
}
// parent[lRoot] = rRoot;
if (height[lRoot] < height[rRoot]) {
parent[lRoot] = rRoot;
} else if (height[rRoot] < height[lRoot]) {
parent[rRoot] = lRoot;
} else {
parent[lRoot] = rRoot;
height[rRoot]++;
}
return 1;
}
int main(void) {
int edgeCount = 6, vertexCount = 5;
int i;
// 图中的边
int graph[5][2] = {
{0, 1}, {2, 4}, {1, 2}, {1, 3},
{2, 5}
};
int parent[edgeCount];
int height[edgeCount];
init(parent, height, edgeCount);
for (i = 0; i < vertexCount; i++) {
int ret = unionVertex(parent, height, graph[i][0], graph[i][1]);
if (ret == 0) {
printf("%d, %d\n", graph[i][0], graph[i][1]);
printf("find cycle!\n");
return 0;
}
}
printf("no find cycle!\n");
for (i = 0; i < vertexCount; i++) {
printf("%d's parent is: %d\n", i, parent[i]);
}
for (i = 0; i < vertexCount; i++) {
printf("%d's height is: %d\n", i, height[i]);
}
return 0;
}
执行结果:
no find cycle!
0's parent is: 1
1's parent is: 4
2's parent is: 4
3's parent is: 4
4's parent is: -1
0's height is: 0
1's height is: 1
2's height is: 0
3's height is: 0
4's height is: 2
【算法与数据结构】并查集 Disjoint Set的更多相关文章
- 算法手记 之 数据结构(并查集详解)(POJ1703)
<ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元 ...
- ACM数据结构-并查集
ACM数据结构-并查集 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合 ...
- 【算法导论-36】并查集(Disjoint Set)具体解释
WiKi Disjoint是"不相交"的意思.Disjoint Set高效地支持集合的合并(Union)和集合内元素的查找(Find)两种操作,所以Disjoint Set中文翻译 ...
- 【数据结构】【计算机视觉】并查集(disjoint set)结构介绍
1.简述 在实现多图像无序输入的拼接中,我们先使用surf算法对任意两幅图像进行特征点匹配,每对图像的匹配都有一个置信度confidence参数,来衡量两幅图匹配的可信度,当confidence> ...
- 并查集(Disjoint Set)
在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中.这一类问题其特点是看似并不复杂, ...
- POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )
Constructing Roads Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 19884 Accepted: 83 ...
- hdu 4641 K-string SAM的O(n^2)算法 以及 SAM+并查集优化
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末 ...
- hdu 1233(还是畅通project)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)
还是畅通project Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...
- hdu 4641K-string SAM的O(n^2)算法 以及 SAM+并查集优化
转载:http://www.cnblogs.com/hxer/p/5675149.html 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末尾插入一 ...
随机推荐
- mariadb主从架构
mariadb主从架构(异步)和集群 一般应用的场所是网站,主的机器是可以写可以读,从的机器可以读,也可以写,但不会同步.只有主的机器增删改,从的机器才会同步. 主从至少三个线程:dump.I/O t ...
- KVM虚拟化网卡管理
brctl常用命令 查看当前虚拟网桥状态 brctl show 添加一个网桥 addbr 删除一个网桥 delbr 添加网口 addif 删除网口 delif VALN LAN 表示 Local Ar ...
- SQLServer Transaction Isolation Level
基本用法 -- Syntax for SQL Server and Azure SQL Database SET TRANSACTION ISOLATION LEVEL { READ UNCOMMIT ...
- SpringMVC的数据转换&&数据格式化&&数据校验
1 SpringMVC的数据绑定流程 SpringMVC将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象. ...
- MySQL事务以及特征
1.什么是事务? 在现实生活中,我们往往会进行转账操作.转账可以分为两部分完成,转入和转出,只要两部分都完成了才算转账完成.在数据库中,这个过程是由两条sql语句来完成的, 如果任意一方的语句没有执行 ...
- 转发(forward)和重定向(redirect)的区别?
1)forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所 ...
- JAVA笔记19-容器之三 Set接口、List接口、Collections类、Comparable接口(重要)
一.Set接口 //HashSet综合举例 import java.util.*; public class Test{ public static void main(String[] args){ ...
- 设计模式来替代if-else
前言# 物流行业中,通常会涉及到EDI报文(XML格式文件)传输和回执接收,每发送一份EDI报文,后续都会收到与之关联的回执(标识该数据在第三方系统中的流转状态).这里枚举几种回执类型:MT1101. ...
- 给DEDECMS广告管理中增加图片上传功能
dedecms的广告管理功能稍微有点次,本文就是在dedecms广告管理原有的基础上增加广告图片上传功能. 安装方法,对应自己的dedecms版本下载对应的编码然后解压把里面的文件放在后台目录覆盖即可 ...
- DevExpress.XtraGrid.Views.Grid.GridView
private void SetView() { GridView gridView = (GridView)this.DefaultView; if (gridView != null) { gri ...