Disjoint-Set Data Structure (Union Find Algorithm)
来源:互联网 发布:季节性过敏性鼻炎知乎 编辑:程序博客网 时间:2024/05/29 12:33
Disjoint-Set数据结构(Union Find Algorithm)
解释不相交数据结构的工作,并有效实施。
问题:我们有一些项目。我们被允许合并任何两个项目,以使它们相等。在任何时候,我们被允许询问两个项目是否被认为是平等的。
什么是Disjoint-Set?
Disjoint-Set是一种数据结构,可以跟踪分割成多个不相交(非重叠)子集的一组元素。换句话说,Disjoint-Set是一组集合,其中没有项可以在多个集合中。它也称为联合查找数据结构,因为它支持联合和查找子集上的操作。让我们从定义开始 -
Find:它确定特定元素在哪个子集中,并返回该特定集合的代表。该集合中的项目通常作为集合的“代表”。
Union:它将两个不同的子集合并成一个子集,一个集合的代表成为其他子集的代表。
Disjoint-Set还支持称为MakeSet的另一个重要操作,它创建一个仅包含给定元素的集合。
union-find如何工作?
通过比较两个查找操作的结果,我们可以确定两个元素是否在同一个子集中。如果两个元素在同一集合中,则它们具有相同的代表,而它们属于不同的集合。如果union被调用两个元素,我们合并两个元素所属的两个子集。
如何实现Disjoint集?
Disjoint-Set forests 是数据结构,其中每个集合由树数据表示,其中每个节点保存对其父节点的引用,并且每个集合的代表是该集合的树的根。
查找父节点直到到达根。
通过将一棵树的根连接到另一棵树的根部,将两棵树结合成一棵树。
例如,考虑如下图所示的由树表示的五个Disjoint-Set sets S1,S2,S3,S4和S5。每个集合最初只包含一个元素,因此它们的父指针指向自身或NULL。
S1 = {1},S2 = {2},S3 = {3},S4 = {4}和S5 = {5}
元素i上的查找操作将返回Si的代表,其中1 <= i <= 5,即Find(i)= i
union-find
如果我们union(S3,S4),S3和S4将被合并成一个不相交的集合S3。现在
S1 = {1},S2 = {2},S3 = {3,4}和S5 = {5}。
Find(4)将返回S3的代表。即Find(4)= 3
union-find-1
如果我们联合(S1,S2),S1和S2将被合并成一个不相交的S1。现在
S1 = {1,2},S3 = {3,4}和S5 = {5}。
查找(2)或查找(1)将返回S1的代表。即Find(2)= Find(1)= 1
union-find-2
如果我们联合(S3,S1),S3和S1将被合并成一个不相交的集合S3。现在
S3 = {1,2,3,4}和S5 = {5}。
union-find-3
实现这些的一种方法可能是:
函数MakeSet(x)
x.parent = x
函数Find(x)
if x.parent == x return xelse return Find(x.parent)
函数Union(x,y)
xRoot = Find(x)yRoot = Find(y)xRoot.parent = yRoot
以下是Union-Find的C ++实现 - 使用Hashtable实现Disjoint集合的。
#include <bits/stdc++.h>using namespace std;//表示一个不相交的集合class DisjointSet { unordered_map<int, int> parent;public: //执行MakeSet操作 void makeSet(vector<int> universe) { //创建n个不相交的集合(每个项目一个) for (int i : universe) parent[i] = i; } //找到元素k所属的集合的根 int Find(int k) { //如果k是根 if (parent[k] == k) return k; //递归为父,直到找到根 return Find(parent[k]); } //执行两个子集的联合 void Union(int a, int b) { //找到元素x和y所属的集合的根 int x = Find(a); int y = Find(b); parent[x] = y; }};void printSets(vector<int> universe, DisjointSet &ds){ for (int i : universe) cout << ds.Find(i) << " "; cout << endl;}// 主函数int main(){ vector<int> universe = { 1, 2, 3, 4, 5 }; // 初始化DisjointSet class DisjointSet ds; //为universe 的每个元素创建单例集 ds.makeSet(universe); printSets(universe, ds); ds.Union(4, 3); // 4和3是同一组 printSets(universe, ds); ds.Union(2, 1); // 1和2是同一组 printSets(universe, ds); ds.Union(1, 3); // 1,2,3,4是同一组 printSets(universe, ds); return 0;}
输出:
1 2 3 4 51 2 3 3 51 1 3 3 53 3 3 3 5
上述方法不比链表方法更好,因为它创建的树可能非常不平衡;然而,它可以通过两种方式增强。
第一种方式,称为union by rank,总是将较小的树附加到较大树的根。由于是影响运行时间的树的深度,所以较深的树的深度树被添加到较深的树的根之下,如果深度相等则仅增加深度。单元素树被定义为具有零等级,并且当相同秩r的两个树组合时,结果的等级为r + 1。对于联盟或查找操作,最坏的运行时间提高到O(log n)。
第二个改进,称为path compression,是一种在使用“查找”时平铺树的结构的方式。这个想法是在到根节点的路上访问的每个节点也可以直接附加到根节点;他们都有同样的代表。为了实现这一点,当Find以递归方式遍历树时,它会将每个节点的父引用更改为指向其找到的根。所产生的树更加平坦,加速未来的行动,不仅仅是对这些要素,而且直接或间接地引用它们。
改进的MakeSet和Union的伪代码:
function MakeSet(x) x.parent = x x.rank = 0function Union(x, y) xRoot = Find(x) yRoot = Find(y) if xRoot == yRoot return // x and y are not already in same set. Merge them. if xRoot.rank < yRoot.rank xRoot.parent = yRoot else if xRoot.rank > yRoot.rank yRoot.parent = xRoot else yRoot.parent = xRoot xRoot.rank = xRoot.rank + 1
这两种技术相辅相成,每次运行的运行时间实际上是一个小常数。
C ++实现 -
#include <bits/stdc++.h>using namespace std;//表示一个不相交的集合class DisjointSet { unordered_map<int, int> parent; //存储树的深度 unordered_map<int, int> rank;public: //执行MakeSet操作 void makeSet(vector<int> universe) { //创建n个不相交的集合(每个项目一个) for (int i : universe) { parent[i] = i; rank[i] = 0; } } //找到元素k所属的集合的根 int Find(int k) { //如果k不是根 if (parent[k] != k) //路径压缩 parent[k] = Find(parent[k]); return parent[k]; } //执行两个子集的联合 void Union(int a, int b) { //找到元素x和y所属的集合的根 int x = Find(a); int y = Find(b); //如果x和y存在于同一集合中 if (x == y) return; //找到元素x和y所属的集合的根 if (rank[x] > rank[y]) parent[y] = x; else if (rank[x] < rank[y]) parent[x] = y; else { parent[x] = y; rank[y]++; } }};void printSets(vector<int> universe, DisjointSet &ds){ for (int i : universe) cout << ds.Find(i) << " "; cout << endl;}// 主函数int main(){ // universe of items vector<int> universe = { 1, 2, 3, 4, 5 }; // initalize DisjointSet class DisjointSet ds; // create singleton set for each element of universe ds.makeSet(universe); printSets(universe, ds); ds.Union(4, 3); // 4和3是同一组 printSets(universe, ds); ds.Union(2, 1); // 1和2是同一组 printSets(universe, ds); ds.Union(1, 3); // 1,2,3,4是同一组 printSets(universe, ds); return 0;}输出: 1 2 3 4 51 2 3 3 51 1 3 3 53 3 3 3 5
联合查找算法的应用:
1.实现Kruskal算法以找到图的最小生成树。
2.在非定向图中检测周期
阅读全文
0 0
- Disjoint-Set Data Structure (Union Find Algorithm)
- Union-find and Disjoint Set Union
- Disjoint set(并查集) data structure
- LeetCode基础--Union Find(Disjoint Set)
- disjoint set (union-find set) (并查集)
- Disjoint Sets--Data Structure
- Disjoint-set Data Structures
- Disjoint-set Data Structures
- Data Structures (Weiss) Chapter 8: Union and Find, Disjoint Sets, union by sizes, C++
- algorithm and data structure
- algorithm and data structure
- Data Structure and Algorithm
- [Algorithm]九章八:Data Structure
- android data structure And algorithm
- Algorithm and Data Structure Review
- [Data Structure and Algorithm]--Heap
- [Data Structure & Algorithm]Sort Algorithms
- 【索引】 Advanced Data Structures :: Disjoint Set
- 写给非专业人士看的 Shadowsocks 简介
- 风控之乱:零经验者,跳槽3次,年薪50万 2016-10-20 20:06 来源:一本财经(yibencaijing) 本文经授权转载!感谢原作者的辛勤创作! 金融的核心是什么? 严谨的金融从业者,
- Orcale必备
- poj 3101 Astronomy 分数lcm+大数java
- DPDK support for vhost-user学习笔记
- Disjoint-Set Data Structure (Union Find Algorithm)
- 编译时注解参考文献
- (DP,分组背包) I love sneakers! -- HDOJ
- genymotion运行问题总结
- python concurrent.futures 简单应用
- Android 从 ftp下载图片到本地
- js加载更多
- Android HTTPS、TLS版本支持相关解决方案 (2)
- 剑指offer——用两个栈实现队列