欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

并查集

程序员文章站 2022-06-23 12:51:22
...

并查集:并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。也就是说在合并的时候不需要考虑两个集合之间的元素是否会重合。


并查集顾名思义:并与查
并者:合并两个集合
查者:查找元素在哪个集合中

每个集合有一个根(root),root的id也就是集合的id。当查找一个元素的时候其实返回的是root的id。

Disjoint-set/Union-find Forest
Find(x): find the root/cluster-id of x
查找x的根结点
Union(x, y): merge two clusters
合并x, y所在的集合

在O(1)*时间内查询2个元素是否在同一个集合里面

Find: O(ɑ(n))* ≈ O(1)

Union: O(ɑ(n))* ≈ O(1)

Space: O(n)
空间复杂度: O(n)

时间复杂度: Find O(n) 未优化的情况。

2个关键优化
路径压缩,把树压扁
按秩排序。把秩小的树合并到秩大的树下面

并查集

并查集

public class UnionFind {
    private int[] parent;
    private int[] weight;
    private int size;

    public UnionFind(int size) {
        this.parent = new int[size];
        this.weight = new int[size];
        this.size = size;
        for (int i = 0; i < size; i++) {
            this.parent[i] = i;//每个结点的代表结点就是自己
            this.weight[i] = 1;//每个代表结点都只有自己一个子节点
        }
    }

    public int find(int element) {
        while (element != parent[element]) {
            parent[element] = parent[parent[element]];//压缩高度
            element = parent[element];
        }
        return element;
    }

    public boolean isConnected(int firstElement, int secondElement) {
        return find(firstElement) == find(secondElement);
    }

    public void unionElements(int firstElement, int secondElement) {
        int firstRoot = find(firstElement);
        int secondRoot = find(secondElement);

        //如果已经属于同一个集合了,就不用再合并了。
        if (firstRoot == secondRoot) {
            return;
        }
        //谁的子节点多久合并到它的下面
        if (weight[firstRoot] > weight[secondRoot]) {
            parent[secondRoot] = firstRoot;
            weight[firstRoot] += weight[secondRoot];
        } else {
            parent[firstRoot] = secondRoot;
            weight[secondRoot] += weight[firstRoot];
        }
    }

    private void printArr(int[] arr){
        for(int p : arr){
            System.out.print(p+"\t");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int n = 10;
        UnionFind union = new UnionFind(n);

        System.out.println("初始parent:");
        union.printArr(union.parent);
        System.out.println("初始weight:");
        union.printArr(union.weight);

        System.out.println("连接了5 6 之后的parent:");
        union.unionElements(5, 6);
        union.printArr(union.parent);
        System.out.println("连接了5 6 之后的weight:");
        union.printArr(union.weight);

        System.out.println("连接了1 2 之后的parent:");
        union.unionElements(1, 2);
        union.printArr(union.parent);
        System.out.println("连接了1 2 之后的weight:");
        union.printArr(union.weight);

        System.out.println("连接了2 3 之后的parent:");
        union.unionElements(2, 3);
        union.printArr(union.parent);
        System.out.println("连接了2 3 之后的weight:");
        union.printArr(union.weight);

        System.out.println("连接了1 4 之后的parent:");
        union.unionElements(1, 4);
        union.printArr(union.parent);
        System.out.println("连接了1 4 之后的weight:");
        union.printArr(union.weight);

        System.out.println("连接了1 5 之后的parent:");
        union.unionElements(1, 5);
        union.printArr(union.parent);
        System.out.println("连接了1 5 之后的weight:");
        union.printArr(union.weight);

        System.out.println("1  6 是否连接:" + union.isConnected(1, 6));

        System.out.println("1  8 是否连接:" + union.isConnected(1, 8));
    }
}
  • LeetCode 399. Evaluate Division
  • LeetCode 547. Friend Circles
  • LeetCode 684. Redundant Connection
  • LeetCode 685. Redundant Connection II
  • LeetCode 839. Similar String Groups