并查集加路径压缩

211 阅读2分钟

并查集(Disjoint-Set Union,简称DSU)是一种用于处理集合合并与查找问题的数据结构和算法。它主要用于维护一组不相交的集合,通常支持以下两种主要操作:

  1. 合并(Union) :将两个集合合并成一个集合,通常是将两个集合的根节点连接在一起。
  2. 查找(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]; //更新老大元素个数
}