不相交集合-并查集
来源:互联网 发布:七秀正太捏脸数据 编辑:程序博客网 时间:2024/05/16 07:28
并查集的定义
不相交集合维护了一个不相交动态集的集合。我们用一个代表来标示每个集合,而这个代表是这个集合的某个成员。
该集合中最主要的两个操作Union(合并)与Find(查询),因此该数据结构也叫做并查集。让我们看一下百度百科的介绍:
在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。——百度百科
可以看出我们只是想要查找某个元素所在的集合或者判断两个元素是否是属于同一个集合,并没有必要把查找的路径返回,这也正是并查集的特点。
并查集的操作
根据并查集的特点,可以得到并查集的基本操作.
在一个不相交集较快的实现方式中,我们使用有根树来表示集合,树中每个节点包含一个成员,每棵树代表一个森林,从而多个集合构成了一个不相交集合森林。数中每个节点仅指向其父节点,如下图(图来自算法导论)。
对于这样的实现方式,每个操作的具体流程如下。
Make-Set
对于集合的存储,我们可以选择最简单的数组,数组存储每个元素的父节点。一开始创建没个小集合时,该集合的父节点就是其本身。
int group[MAXN];void make_set(int x) { /*创建一个单元集*/ group[x] = x; }
Union
上述图中的最右边的树就是左边两颗树合并之后的结果。这种情况下Union的操作是非常简单的。
void Union(int x,int y){ group[find(x)] = find(y);}
合并两个节点只需将一个节点的根节点的父亲设定为另外一个节点的根节点即可。
Find-Set
查找某个元素所属的集合,即是查找该元素所在树的根节点,因此最后经过若干次查找,一个节点总是能够找到它的根节点,即满足group[root] = root的节点也就是树的根节点了。
int find(int x) { // 寻找x节点所在组的根节点,根节点具有性质group[root] = root while (x != group[x]) x = group[x]; return x; }
按秩合并与路径压缩
按秩合并
在进行Union时,若能将较少节点的树根指向节点较多的树根,而不是反过来,这样能够让树看起来更加的平衡,并且更加有利于find操作。因此我们拿出额外的空间来存储每个节点的秩,这个秩表示了该节点高度的一个上届,Union操作时,可以让较小高度的秩指向较大高度的秩。
路径压缩
不断地Union之后,有可能出现树的高度很高的极端情况,这样Find操作的效率较低,使用路径压缩可以使查找路径的每个节点直接指向根。如下图:
b图是指向了Find-Set之后的的同一个集合,现在查找路径上每个节点都指向了根。
那么加入按秩合并和路径压缩之后的代码如下:
int group[MAXN]; int rank[MAXN]; /*rank[x]是x的高度的一个上界*/void make_set(int x){ /*创建一个单元集*/ group[x] = x; rank[x] = 0;}int find_set(int x){ /*带路径压缩的查找*/ if(x != group[x]) group[x] = find_set(group[x]); return group[x];}/*按秩合并x,y所在的集合*/void union_set(int x, int y){ x = find_set(x); y = find_set(y); if(rank[x] > rank[y])/*让rank比较高的作为父结点*/ group[y] = x; else { group[x] = y; if(rank[x] == rank[y]) rank[y]++; }}
上述的Find-Set值得一提,其是一种两趟方法,递归时沿着路径找到根节点,回溯时,更新每个节点,使其指向根。
时间复杂度
使用了路径压缩和按秩合并之后,整个并查集的时间复杂能与总操作数m呈线性关系。最坏情况是O(mx(n)),x(n)是一个增长非常慢的函数。具体的证明请参考算法导论21.4节,过程并不简单,这里不再论述。
- 不相交集合 - 并查集
- 并查集(不相交集合)
- 不相交集合 - 并查集
- 并查集(不相交集合)
- 不相交集合(并查集)
- 不相交集合-并查集
- 并查集(不相交集合)基础知识详解
- 用于不相交集合的数据结构(并查集)
- 不相交集合的数据结构-并查集
- 【并查集】 不相交集合 - 并查集 教程(文章作者:Slyar)
- 【并查集】 不相交集合 - 并查集 教程(文章作者:Slyar)
- 并查集(不相交集)
- 不相交集(并查集)(C++)
- 不相交集(并查集)
- 并查集及其链表与不相交集合森林实现
- 实用算法实现-第12篇不相交集合(并查集)
- [算法导论读书笔记]用于不相交集合的数据结构(并查集)
- 【算法与数据结构】不相交集合——并查集
- eclipse 安装tomcat插件
- Android 开发笔记——通过 Intent 传递类对象
- php技巧总结(待续)
- OC_继承,便利构造器,初始化方法
- Android源码目录结构
- 不相交集合-并查集
- linux下安装R
- Spark 模型总结
- Spring的注解配置和XML配置的比较
- 快排的两种写法
- Java上转型对象
- 041.Char Array 字符数组
- iptable中snat和masquerade的区别
- java我的总结——一些基础知识和代码