并查集 Union-Find-Set
来源:互联网 发布:有限元软件在线培训 编辑:程序博客网 时间:2024/05/16 09:42
先看这样一个问题:若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
这样一类问题,若使用常规的数据结构进行表述和存储,当数据量很大时会带来很大的数据内存开销,因为需要将所有的关系对都描述清楚确实繁琐又容易出错,而且存储量开销大的情况下下进行相关的查找和其他操作也变得时间消耗过大。为了解决这样一类问题,便使得并查集这样一种简单的数学处理方式渐渐走进人们的视野。
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中,当所有顶点都处理完之后就可以得到一个或者多个顶点集合,所有相交元素都处于同于集合。并查集能够实现较快的合并和判断元素所在集合的操作,利用这样一种特性,我们可以轻易的求得图是否连通,网络是否连通等问题。
并查集的操作通常有三个:
1> 初始化:初始化所有的单个元素到单个集合(Init_Set),使得每个元素的root节点都能标志当前集合,常用的方式有,Father[i] = i 或者 Father[i] = 0.
2> 查找: 查找给定的元素所属集合(Find_Set),查找方式就是找到改X元素在所在集合的root标志节点,也就是祖先节点,相同集合的元素拥有相同的祖先节点root,更具这个标记就可以判断不同的元素是否属于相同的集合。
3> 合并:将不相同集合的元素进行合并(Union_Set)。利用第二部查找找到的两个集合的root标记,若两个元素不属于相同的集合即x和y,也就是x和y对应的的root不相同。就可以将x和y集合进行合并,将一个集合的祖先指向另一个集合的祖先,使得他们最终有相同的root标记。
代码如下:
int Father[N];//初始化集合.每个集合的标记都是它本身void init_set(int n) {for(int i=0; i < n; i++) { Father[i] = i; } }// 递归查找到x的祖先节点int find_set(int x) {while(x != Father[x])x = Father[x];return x; }// 合并X和Y两个集合void union_set(int x,int y) {int xroot = find_set(x);int yroot = find_set(y);// 不属于相同集合则合并if (xroot != yroot) {Father[xroot] = yroot;}}
并查集的优化:路径压缩
每一次执行find查找集合的祖先标记节点时,都是最花费时间的,尤其是当所有的合并完成后集合的状态变成一个单支树时,其时间复杂度就变成了O(n),大量的查找将会耗费特别大的代价。如何优化这个时间复杂度么,常规的方法就是采用状态路径压缩,就是将我们找到的集合的祖先节点后,在查找的时候进行路径压缩将改集合的所有子孙节点都指向同一个祖先节点,这样单支结构就变成了多叉树的结构,从而使得后面的每次查找find_set的时间开销都变成了O(1)。如下图所表示的结构变化:
优化代码如下所示:
int Father[N];int Rank[N];// 用来标记集合的秩//初始化集合.每个集合的标记都是它本身void init_set(int n) {for(int i=0; i < n; i++) { Father[i] = i; Rank[i] = 0; // 初始化每个集合的秩为0} }// 递归查找到x的祖先节点int find_set(int x) {// 每次查找时都将上一次的合并进行路径// 压缩从而使得下一次的查找时间变得更短if (x != Father[x]){//回溯压缩路径Father[x] = find_set(Father[x]);}return Father[x];}// 合并X和Y两个集合void union_set(int x,int y) {int xroot = find_set(x);int yroot = find_set(y);if (xroot == yroot) return;if (Rank[xroot] > Rank[yroot]){// 如果x的秩大于y的,将y指向xFather[yroot] = xroot;}else{// 当秩相同时 改变其中一个集合的秩if (Rank[xroot] == Rank[yroot])Rank[yroot]++;// 将秩小的集合指向秩高的集合 进行合并Father[xroot] = yroot;}// 不属于相同集合则合并if (xroot != yroot) {Father[xroot] = yroot;}}
- 并查集(Union-Find Set)
- 并查集 Union-Find-Set
- 并查集(Union-Find Set)小结
- disjoint set (union-find set) (并查集)
- 并查集(union-find set or DisjointSets)
- 一、并查集 (Union-Find Set)
- Union-Find Set 并查集 详解 [基本模板]
- 并查集(union-find set)与Kruskal算法
- 并查集(Union-Find Set)模板
- 并查集(Union-Find)
- Union Find 并查集
- 并查集Union--Find
- 并查集Union-Find
- union-find(并查集)
- 并查集- Union-Find
- union find(并查集)
- 并查集 (Union-Find Sets)
- 并查集 (Union-Find Sets)
- 鼻炎,太阳穴酸痛
- LevelDb日知录之一:初识LevelDb
- Head First 装饰模式
- Hibernate HQL
- Android自定义属性时TypedArray的使用方法
- 并查集 Union-Find-Set
- Android SQLite事务操作
- 在数据库中使用asm
- Android系统中如何监听来电和去电
- LevelDb日知录之二整体架构
- AOP技术应用和研究
- HashMap,LinkedHashMap,TreeMap的区别
- html中submit和button的区别(总结)
- Redis核心结构字典