并查集(Disjoint-Set Union,简称DSU)是一种用于处理集合合并与查找问题的数据结构和算法。它主要用于维护一组不相交的集合,通常支持以下两种主要操作:
- 合并(Union) :将两个集合合并成一个集合,通常是将两个集合的根节点连接在一起。
- 查找(Find) :确定一个元素属于哪个集合,通常是查找元素所在集合的根节点。
路径压缩是并查集中的一个优化技巧,旨在减少树的深度,从而提高查找操作的效率。在路径压缩中,当进行查找操作时,会将查询路径上的每个节点直接链接到根节点。这意味着在以后的查询中,相同集合的元素可以更快地找到它们的根节点,因为路径已经被压缩,不再需要遍历整个树。
路径压缩的一种常见实现方式是使用递归。当你查找一个元素的根节点时,递归地遍历查找路径上的每个节点,将它们直接链接到根节点。这会导致树的深度变得非常小,几乎是常数级别,从而提高了查找操作的效率。
本文是对union方法按照小弟的个数进行的路径压缩,也可以通过修改find方法来进行路径压缩,此外,还有其它的压缩方法,比如根据树的深度进行压缩。
public class DisjointSetUnionBySize {
int[] s;
//用于路径压缩
int[] size;
public DisjointSetUnionBySize(int size) {
s = new int[size];
this.size = new int[size];
for (int i = 0; i < size; i++) {
s[i] = i;
this.size[i] = 1;
}
}
//找老大
public int find(int x) {
if (x == s[x]) {
return x;
}
return find(s[x]);
}
//union 是让两个集合"相交",即选出新老大,x、y是原老大索引
public void union(int x, int y) {
if (size[x] < size[y]) {
//y老大 x小弟
s[x] = y;
size[y] = size[x] + size[y]; //更新老大元素个数
}else {
// x 新老大 y 新小弟
s[y] = x;
size[x] = size[x] + size[y]; //更新老大元素个数
}
}
@Override
public String toString() {
return "内容"+Arrays.toString(s)+"\n大小: "+Arrays.toString(size);
}
public static void main(String[] args) {
DisjointSetUnionBySize set = new DisjointSetUnionBySize(5);
set.union(1, 2);
set.union(3, 4);
set.union(1, 3);
System.out.println(set);
set.union(0, 1);
System.out.println(set);
}
}
//另一种写法
public void union(int x, int y) {
if(size[x] < size[y]){
int t =x ;
x = y;
y =t;
}
// x 新老大 y 新小弟
s[y] = x;
size[x] = size[x] + size[y]; //更新老大元素个数
}