算法来自Algorithms一书1.5节,在此备忘。
该书配套网站:http://algs4.cs.princeton.edu/15uf/
算法解决的问题
解决的是动态连通性问题,给定N个点和N个点之间的连通数据,例如:
N = 10(0,1,2,3,4,5,6,7,8,9)
连通数据:
(4,3)
(3,8)
(6,5)
(9,4)
(2,1)
(8,9)
(5,0)
(7,2)
(6,1)
(1,0)
(6,7)
效果图如下:

问题就是,如何判断给定的两个点是连通的?比如上图中,(8,9)、(1,0)、(6,7)都是连通的。如何判断这些节点中有多少个连通分量(孤岛,如上面的数据构成的节点就存在两个相互独立的孤岛)?
quick-find算法:
该算法的思路是创建一个长度为N的数组,数组的每一个元素表示一个点,依靠判断两个数组元素的值是否相同来判断这两个元素是否是连通的,数组元素的初始值为点的序号,表示他们互不相连。新加入一个连接时,需要将连接双方的每一个点的值都改成一致的。
public class QuickFindUF {
private int[] id;
private int count;
public QuickFindUF(int N){
id = new int[N];
for(int i = 0;i<N;i++){
id[i] = i;
}
count = N;
}
public int find(int p){
return id[p];
}
//union q to p
public void union(int p,int q){
int pId = find(p);
int qId = find(q);
if(pId==qId) return;
for(int i = 0;i<id.length;i++){
if(id[i]==qId){
id[i] = pId;
}
}
count--;
}
public boolean connected(int p,int q){
return find(p) == find(q);
}
public int count(){
return count;
}
public static void main(String[] args) {
int N = StdIn.readInt();
QuickFindUF uf = new QuickFindUF(N);
while(!StdIn.isEmpty()){
int p = StdIn.readInt();
int q = StdIn.readInt();
if(uf.connected(p, q)){
continue;
}
uf.union(p, q);
StdOut.println(p + " " + q);
}
StdOut.println(uf.count()+" compontents");
}
}
quick-union算法
quick-union算法在对节点值的定义上有所不同,表示的是父节点,从而把所有节点变成了树状结构。
quick-find算法的时间主要浪费在union上,改进的quick-union算法的union方法进行了优化,不需要遍历所有节点。这主要依赖于find方法,find方法查找的不是节点本身,而是节点所属的根节点:
public class QuickUnionUF {
private int[] id;
private int count;
public QuickUnionUF(int N){
id = new int[N];
for(int i = 0;i<N;i++){
id[i] = i;
}
count = N;
}
public int find(int p){
while(id[p]!=p){
p = id[p];
}
return id[p];
}
//union q to p
public void union(int p,int q){
int pId = find(p);
int qId = find(q);
if(pId==qId) return;
id[pId] = qId;
count--;
}
public boolean connected(int p,int q){
return find(p) == find(q);
}
public int count(){
return count;
}
public static void main(String[] args) {
int N = StdIn.readInt();
QuickUnionUF uf = new QuickUnionUF(N);
while(!StdIn.isEmpty()){
int p = StdIn.readInt();
int q = StdIn.readInt();
if(uf.connected(p, q)){
continue;
}
uf.union(p, q);
//StdOut.println(p + " " + q);
}
StdOut.println(uf.count()+" compontents");
}
}
加权重的quick-union算法
quick-union的缺点是,在最坏情况的输入数据时,最后形成的树可能是畸形的,树的深度很大,导致find方法查找根节点的时间代价越来越大。加权重的quick-union算法增加了每个节点的权重值。在初始时每个节点的权重是相同的,当节点不断地聚集,根节点的权重不断增大。union的时候,根据权重就能将小树连接到大树上,不会出现将大树连接到小树的情况,从而保证树的深度不会很大。
public class WeightedQuickUnionUF {
private int[] id;
private int[] weight;
private int count;
public WeightedQuickUnionUF(int N){
System.out.println("size=" +N);
id = new int[N];
weight = new int[N];
for(int i = 0;i<N;i++){
id[i] = i;
weight[i] = 1;
}
count = N;
}
public int find(int p){
while(id[p]!=p){
p = id[p];
}
return id[p];
}
//union q to p
public void union(int p,int q){
int pId = find(p);
int qId = find(q);
if(pId==qId) return;
if(weight[pId] < weight[qId]){
//connect p to q
id[pId] = qId;
weight[qId] += weight[pId];
}else{
//connect q to p
id[qId] = pId;
weight[pId] += weight[qId];
}
count--;
}
public boolean connected(int p,int q){
return find(p) == find(q);
}
public int count(){
return count;
}
public static void main(String[] args) {
int N = StdIn.readInt();
WeightedQuickUnionUF uf = new WeightedQuickUnionUF(N);
while(!StdIn.isEmpty()){
int p = StdIn.readInt();
int q = StdIn.readInt();
if(uf.connected(p, q)){
continue;
}
uf.union(p, q);
//StdOut.println(p + " " + q);
}
StdOut.println(uf.count()+" compontents");
}
}
总的来说,quick-find方法不是基于树来考虑的,跟多的是基于分组的思想,最终的结果是不同的孤岛中的点都保存着相同的组号。quick-union算法则是基于树的思想,两个树想连的时候,不会对树的子节点进行任何操作,仅仅是对树的根节点进行调整,这就避免了从新调整节点值的操作。这种情况下,如果再保证树的深度不是很大,就能迅速提高运行速度。
分享到:
相关推荐
ACM并查集算法学习 并查集是一种数据结构算法,顾名思义就是有“合并集合”和“查找集合”两种操作。一般来说,一个并查集有三个操作:初始化、查找函数和合并集合函数。 一、初始化 初始化包括对所有单个的数据...
并查集(Disjoint Set)和确定有限状态...学习并查集和DFA,不仅可以掌握基础的算法思想,还能为学习更复杂的算法打下坚实基础。通过实际编写代码和解决相关问题,可以更好地理解这两种工具的工作原理和应用场景。
最后,课程讲解了 union-find 算法的基本概念,包括如何使用union-find来解决连通分量问题等。 本节课程涵盖了多种数据结构和算法思想,为后续学习奠定了基础。通过深入学习和实践,学生可以熟练掌握这些知识点,并...
这部分提供了实用的算法实现模板,例如线段树(Segment Tree)和并查集(Union Find)。这些模板可以帮助初学者更快地理解和实现算法,减少编程过程中的重复工作。 ##### 5. 第四章:LeetCode题解 这一章节是整个文档...
并查集(Union-Find)是一种用于处理连接关系的数据结构,它在计算机科学中有着广泛的应用,尤其是在图论、算法设计以及数据结构的学习中。这个数据结构的主要目标是高效地解决“查找”和“合并”两个操作,常用于...
6. **并查集(Union-Find)**:011_15UnionFind.pdf 是一种数据结构,用于维护一组不相交集合的并运算和查运算。在解决连接组件、寻找连通性等问题时非常有效。 7. **最小生成树(Minimum Spanning Trees)**:071_43...
图论是算法中较为复杂的领域之一,Labuladong在图论部分介绍了图的基本概念、拓扑排序、二分图判定和Union-Find算法等内容。这些知识不仅对解决网络流、最短路径等经典问题有帮助,也是面试中经常被问到的高频考点。...
在编程和算法学习中,库文件扮演着至关重要的角色,它们提供了一系列预定义的函数和类,方便开发者快速实现特定功能。"算法第四版所需要用到的stdlib.jar algs4.jar"这个标题揭示了这两个jar文件是专为配合《算法第...
#### Union-Find算法详解、算法应用 - Union-Find(并查集)算法的原理、实现和应用。 #### 二分查找高效判定子序列 - 讲解二分查找算法如何判定一个序列是另一个序列的子序列。 ### 第五章:计算机技术 #### ...
1. **并查集(Union-Find)**:并查集是一种处理集合合并与查询的数据结构,常用于解决连通性问题。通过路径压缩和按秩合并等优化,其操作效率接近常数级别,但在最坏情况下时间复杂度分析较为复杂。 2. **KMP字符串...
- 图论基础、拓扑排序、二分图判定、Union-Find算法及其应用也在此部分展开。 4. **暴剑篇 - 暴力搜索算法**: - 回溯算法和深度优先搜索(DFS)的解题框架,展示了如何解决集合划分、子集、排列等问题。 - 宽度...
通过STL,程序员可以方便地使用已有的高效实现,如排序算法(sort)、查找算法(find、binary_search)和集合操作(union、intersection)。同时,STL的模板机制使得代码具有高度的可重用性和泛型性。 书中可能涵盖...
总之,《数据结构基本算法大全》Word版是一本难得的算法学习资料,它系统地介绍了数据结构和算法的核心知识,使得读者能够通过这些具体算法的学习,深化对计算机科学基础的理解,提升解决实际问题的能力。...
通过这个算法,学生可以学习如何在有限的容量下,选择价值最大或重量最小的物品进行组合。 2. Dijkstra算法:用于寻找图中两点间的最短路径,广泛应用于路由选择和网络优化。Dijkstra算法保证了找到的路径是最优的...
在编程和计算机科学领域,算法设计是至关重要的一个部分,...以上只是这份资料中部分算法设计的概述,每一个话题都包含着丰富的理论和实践价值,深入学习和掌握这些算法,将对提升编程技能和解决实际问题能力大有裨益。
- Union-Find算法:一种数据结构,用于高效处理动态连通性问题。 - Linux进程、线程、文件描述符的介绍。 - 算法问题的简单一行代码解决方法。 以上内容涉及了编程中的算法和数据结构的多个方面,涵盖了动态规划、...
leetcode 答案 算法 数据结构和算法实现 C++实现,使用Googletest框架测试 ...UnionFind.h │ ├── Hash │ │ └── Hash.h │ ├── Queue │ │ ├── DHeap.h │ │ ├── Deque
《严蔚敏数据结构与算法实现》是一本深入探讨数据结构和算法的教材,其中"02 Union"部分主要涉及图论中的并查集(Union-Find)算法。...这对于理解和解决实际问题具有重要意义,是数据结构与算法学习过程中的重要一环。
- **合并-查找(Union-Find)**:一种高效的处理不相交集合合并与查找的算法。在渗透问题中,它用于快速判断两个格点是否属于同一个连通分量。 - **N×N网格**:表示渗透系统的二维数组,用以存储每个格点的状态...