博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并查集(Union-Find)
阅读量:4360 次
发布时间:2019-06-07

本文共 3653 字,大约阅读时间需要 12 分钟。

一、基本操作:

1、Find:当且仅当两个元素属于相同的集合时,返回相同的名字

2、Union:将两个不相交的集合合并为一个不想交的集合。

应用:在等价关系中,判断两个元素之间是否有关系或者添加等价关系。

二、基本数据结构

1、Quick-Find实现

采用一个数组保存每个等价类的名字,这种实现下Find的复杂度为O(1),而Union实现的复杂度为O(n)。

例如Union(i,j):Union操作需要遍历整个数组,将所有为j的元素改为i。

1 public class ADTQuickFind { 2     private int[] id; 3     private int size; 4     public ADTQuickFind(int size){ 5         this.size = size; 6         id = new int[size]; 7         //初始化默认所有节点不联通 8         for(int i = 0; i < size; i++) 9             id[i] = i;10     }11 12     public int find(int p){13         //p的值出现异常14         if(p < 0 || p >= size)15             return  -1;16         return id[p];17     }18 19     public void Union(int p, int q){20         int pId = find(p);21         int qId = find(q);22         if(pId == qId)23             return;24         for(int i = 0; i < size; i++){25             if(id[i] == qId)26                 id[i] = pId;27 28         }29     }30 31     public boolean isRelated(int p, int q){32         return find(p) == find(q);33     }34 }

如果最开始所有元素都不连通,那么最多执行N-1次Union运算,此时所有的元素都在一个等价类中,总的时间复杂度为O(n2)。

如果Find运算比较多的情况下,存在Ω(n2)次Find运算,那么平均每次Find或者Union的时间复杂度为O(1),但是如果Find的次数比较少,那么这种方法是不可以接受的。

2、Quick-Union实现

在数组中隐式地存储一个森林,每个数组对应的位置存储对应节点的父节点的编号,树根节点保存自己的编号。

Find:由于Find操作要求当且仅当两个元素在相同的集合时,作用在两个元素上的Find操作返回相同的名字。而返回元素的标记是什么并不重要,因此通过返回一个节点的根节点的编号代表节点所处等价类的编号。

Union:使一个节点的根指针指向另一棵树的根节点。

1 public class ADTQuickUnion { 2     int[] parent; 3     int size; 4     public ADTQuickUnion(int size){ 5         this.size = size; 6         parent = new int[size]; 7         for(int i = 0; i < size; i++) 8             parent[i] = i; 9     }10     public int find(int p){11         if(p < 0 || p >= size)12             return -1;   //出现异常值13         while(parent[p] != p)14             p = parent[p];15         return p;16     }17     public void union(int p, int q){18         int pId = find(p);19         int qId = find(q);20         if(pId == qId)21             return;22         parent[qId] = pId;23     }24     public boolean isRelated(int p, int q){25         return find(p) == find(q);26     }27 }

算法中执行Find操作花费的时间与节点的深度成正比,最坏情况下,会建立一个深度为N-1的树,使用一次Find的最坏情形运行时间为O(n)。

3、QuickUnionBetter实现

在Union操作中,将元素个数较少的树插到元素个数较多的树的根节点上。

1 public class ADTQuickUnionBetter { 2     private int[] parent; 3     private int[] mSize; 4     private int size; 5     public ADTQuickUnionBetter(int size){ 6         this.size = size; 7         parent = new int[size]; 8         mSize = new int[size]; 9         for(int i = 0; i < size; i++){10             parent[i] = i;11             mSize[i] = 1;12         }13     }14     public int find(int p){15         if(p < 0 || p >= size)16             return -1;  //表明出现异常值17         while(p != parent[p])18             p = parent[p];19         return p;20     }21     public void union(int p, int q){22         int pId = find(p);23         int qId = find(q);24         if(pId == qId)25             return;26         if(mSize[pId] < mSize[qId]){27             parent[pId] = qId;28             mSize[qId] = mSize[pId] + mSize[qId];29         }30         else{31             parent[qId] = pId;32             mSize[pId] = mSize[qId] + mSize[pId];33         }34     }35     public boolean isRelated(int p, int q){36         return find(p) == find(q);37     }38 }

可以证明,任何节点的深度不会超过log(n),由于随着深度每次随着Union的结果而增大1时,该节点被置于节点数至少为原先两倍大的树上。

因此Find操作的时间复杂度为O(log(n)),连续M次操作的时间复杂度为O(MlogN),平均时间得到证明为O(M)时间,为线性的。

4、Find中优化路径压缩优化路径压缩

1 public int find(int p){2     if(p < 0 || p >= size)3         return -1;  //异常值4     while(p != parent[p]){5         parent[p] = parent[parent[p]];6         p = parent[p];7     }8     return p;9 }

 

转载于:https://www.cnblogs.com/lwyeah/p/8934097.html

你可能感兴趣的文章
【转】iOS静态库 【.a 和framework】【超详细】
查看>>
【转】Android中自定义控件的步骤
查看>>
软件测试工作中的沟通问题
查看>>
format 的用法,9*9乘法表
查看>>
mysql--5
查看>>
uva11214 Guarding the Chessboard
查看>>
CentOS6.4下Git服务器Gitosis安装配置
查看>>
007 斐波那契数列
查看>>
《Docker入门实战》笔记(一)
查看>>
hdu 3635 Dragon Balls (并查集)
查看>>
文件操作
查看>>
7.java集合,泛型简单总结,IO流
查看>>
杭电2007 平方和与立方和
查看>>
JS邮箱验证-正则验证
查看>>
关于SQL查询效率,100w数据,查询只要1秒
查看>>
Quartz 2D绘图
查看>>
JS Fetch
查看>>
EJB 笔记
查看>>
【delete】Android自定义控件(四) 自定义ImageView动态设置ImageView的高度
查看>>
HDUOJ------(1230)火星A+B
查看>>