Union-Find连通性检测之quick-union
理论基础
在图论和计算机科学中,Union-Find 或并查集是一种用于处理一组元素分成的多个不相交集合(即连通分量)的情况,并能快速回答这组元素中任意两个元素是否在同一集合中的问题。Union-Find 特别适用于连通性问题,例如网络连接问题或确定图的连通分量。
Union-Find 的基本操作
Union-Find 数据结构支持两种基本操作:
- Union(合并): 将两个元素所在的集合合并成一个集合。
- Find(查找): 确定某个元素属于哪个集合,这通常涉及找到该集合的“代表元素”或“根元素”。
Union-Find 的结构
Union-Find 通常使用一个整数数组来表示,其中每个元素的值指向它的父节点,这样形成了一种树形结构。集合的“根元素”是其自己的父节点。
Union-Find 的优化技术
为了提高效率,Union-Find 实现中常用两种技术:
- 路径压缩(Path Compression): 在执行“查找”操作时,使路径上的每个节点都直接连接到根节点,从而压缩查找路径,减少后续操作的时间。
- 按秩合并(Union by Rank): 在执行“合并”操作时,总是将较小的树连接到较大的树的根节点上。这里的“秩”可以是树的深度或者树的大小。
应用示例
Union-Find 算法常用于处理动态连通性问题,如网络中的连接/断开问题或者图中连通分量的确定。例如,Kruskal 的最小生成树算法就使用 Union-Find 来选择边,以确保不形成环路。
总结
Union-Find 是解决连通性问题的一种非常高效的数据结构。它能够快速合并集合并快速判断元素之间的连通性。通过路径压缩和按秩合并的优化,Union-Find 在实际应用中可以接近常数时间完成操作。因此,它在算法竞赛、网络连接和社交网络分析等领域有广泛的应用。
数据结构
private int[] id // 分量id(以触点作为索引)
private int count // 分量数量
实验数据和算法流程
本实验使用tinyUF.txt
作为实验数据,数据内容如下,一共定义了10对连通性关系
10
4 3
3 8
6 5
9 4
2 1
8 9
5 0
7 2
6 1
1 0
6 7
实验的目的是检测数据中共有多少个连通分量,并打印每个元素所属的连通分量编号
下图展示了处理5和9连通性的一个瞬间
完整流程如下
代码实现
原则是小树挂在大树下,如果一棵高度为1,但是有100个节点的树,要把高度为2的三节点小树挂在这课大树上
可以想象如果反过来,大树挂在小树下,大树的100个节点都将变成高度为3的树枝,这样的话查询的整体成本就太高了
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdIn;
public class myQuickUnion {
private int[] id;
private int count;
private int finds;
private int[] size;
public myQuickUnion(int N) {
// 初始化分量id数组
count = N;
id = new int[N];
for (int i = 0; i < N; i++) id[i] = i;
size = new int[N];
for (int i = 0; i < N; i++) s