并查集(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的更多相关文章

  1. 算法手记 之 数据结构(并查集详解)(POJ1703)

    <ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元 ...

  2. ACM数据结构-并查集

    ACM数据结构-并查集   并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合 ...

  3. 【算法导论-36】并查集(Disjoint Set)具体解释

    WiKi Disjoint是"不相交"的意思.Disjoint Set高效地支持集合的合并(Union)和集合内元素的查找(Find)两种操作,所以Disjoint Set中文翻译 ...

  4. 【数据结构】【计算机视觉】并查集(disjoint set)结构介绍

    1.简述 在实现多图像无序输入的拼接中,我们先使用surf算法对任意两幅图像进行特征点匹配,每对图像的匹配都有一个置信度confidence参数,来衡量两幅图匹配的可信度,当confidence> ...

  5. 并查集(Disjoint Set)

    在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中.这一类问题其特点是看似并不复杂, ...

  6. POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )

    Constructing Roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19884   Accepted: 83 ...

  7. hdu 4641 K-string SAM的O(n^2)算法 以及 SAM+并查集优化

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末 ...

  8. hdu 1233(还是畅通project)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)

    还是畅通project Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  9. hdu 4641K-string SAM的O(n^2)算法 以及 SAM+并查集优化

    转载:http://www.cnblogs.com/hxer/p/5675149.html 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末尾插入一 ...

随机推荐

  1. Linux学习--第八天--acl、SetUID、SetGID、chattr、lsattr、sudo

    acl权限 文件只能有一个所属组 acl就是不管用户什么组了,直接针对某个文件给他特定权限. acl需要所在分区文件系统的支持. df -h #查看分区 dumpe2fs -h /dev/sda3 # ...

  2. 【转】Linux内核中分配4M以上大内存的方法

    在Linux内核中, kmalloc能够分配的最大连续内存为2的(MAX_ORDER-1)次方个page(参见alloc_pages函数,     "if (unlikely(order & ...

  3. 可持久化BCJ

    BZOJ3674:可持久化并查集加强版 n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出 ...

  4. 第02课:启动GDB调试

    使用GDB调试程序一般有三种方式: gdb filename gdb attach pid dgb filename corename 也对应这本节课的核心内容: 直接调试目标程序 附加进程 调试co ...

  5. SQL优化之表连接方式

    1.嵌套循环(DESTED LOOPS) Note:嵌套循环被驱动表必须走索引,而且索引只能走INDEX UNIQUE SCAN或者INDEX RANGE SCAN SQL> select /* ...

  6. 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Binary

    题目 分析 首先每个数对\(2^i\)取模.也就是把每个数的第i位以后删去. 把它们放进树状数组里面. 那么当查询操作, 答案就位于区间\([2^i-x,2^{i-1}-1-x]\)中,直接查询就可以 ...

  7. python 面向对象_1

    self #self 是相当于c++的 this指针 class Ball: def setName(self,name): self.name = name def kick(self): prin ...

  8. linux-系统启动流程-7

    1,BIOS开机自检,检查cpu硬件及开机启动顺序,查找第一个磁盘磁头的MBR信息并加载BOOtloader,然后将控制权交与bootloader 2, GRUB GRUB(Grand Unified ...

  9. MFC多文档获取窗口句柄

    GET App   AfxGetInstanceHandle()    AfxGetApp()   GET Frame->View->Document     SDI    AfxGetM ...

  10. MongoDB基本操作(增删改查)

    基本操作      基本的“增删查改“,在DOS环境下输入mongo命令打开shell,其实这个shell就是mongodb的客户端,同时也是一个js的编译器,默认连接的是“test”数据库.