Bootstrap

并查集(Java)

1. 定义与概念

并查集(Union - Find Set)是一种处理不相交集合的数据结构,主要用于解决动态连通性问题。它支持两种操作:合并(Union)和查找(Find)。

例如,在一个社交网络中,判断两个人是否属于同一个社交圈子,或者将两个社交圈子合并为一个,就可以使用并查集来高效地解决。

2. 数据结构实现

  • 存储方式:通常使用数组来表示并查集。数组的下标代表元素,数组元素的值代表该元素的父节点。例如,parent[i]表示元素i的父节点。
  • 初始化:开始时,每个元素的父节点是它自己,即parent[i]=i。这表示每个元素自成一个集合。
  • 示例代码如下:
class UnionFind {
    private int[] parent;

    public UnionFind(int n) {
        parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
}

在上述代码中,UnionFind类表示并查集。构造函数UnionFind(int n)用于初始化并查集,创建一个大小为n的数组parent,并将每个元素的父节点初始化为自身。

3. 操作实现

  • 查找(Find)操作
    • 目的是找到元素所属集合的代表元素(通常是集合中某个固定的元素,如根节点)。通过不断地查找元素的父节点,直到找到父节点是自己的元素,这个元素就是代表元素。
    • 示例代码:
public int find(int x) {
    if (parent[x] == x) {
        return x;
    }
    return find(parent[x]);
}

这里,find(int x)方法实现了查找操作。如果parent[x]==x,说明x就是代表元素,直接返回x。否则,继续查找parent[x]的代表元素,递归地调用find(parent[x])

  • 路径压缩优化
    • 在查找操作中,可以进行路径压缩,以减少后续查找操作的时间复杂度。路径压缩的思想是在查找过程中,将查找路径上的所有元素直接连接到代表元素上。
    • 优化后的查找代码如下:
public int find(int x) {
    if (parent[x] == x) {
        return x;
    }
    // 路径压缩
    parent[x] = find(parent[x]);
    return parent[x];
}

parent[x]!=x时,先递归地查找parent[x]的代表元素,然后将parent[x]直接指向这个代表元素,实现了路径压缩。

  • 合并(Union)操作
    • 目的是将两个集合合并为一个。首先找到两个元素所属集合的代表元素,然后将一个代表元素的父节点设置为另一个代表元素,实现集合的合并。
    • 示例代码:
public void union(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);
    if (rootX!= rootY) {
        parent[rootX] = rootY;
    }
}

union(int x, int y)方法中,先通过find操作找到xy所属集合的代表元素rootXrootY。如果rootX!=rootY,说明xy属于不同的集合,将rootX的父节点设置为rootY,实现了集合的合并。

4. 时间复杂度分析

在没有路径压缩优化的情况下,查找操作的时间复杂度最坏为,其中n是元素的个数。经过路径压缩优化后,查找操作的时间复杂度可以近似为,其中是阿克曼函数的反函数,它的增长速度非常慢,在实际应用中可以认为是一个常数。

合并操作的时间复杂度主要取决于查找操作,经过优化后也可以近似认为是一个常数时间操作。

5. 应用场景举例

  • 最小生成树算法(Kruskal's Algorithm):在构建最小生成树时,需要判断加入一条边是否会形成回路。并查集可以高效地判断两个顶点是否属于同一个连通分量,从而决定是否添加边。
  • 社交网络分析:如前面提到的判断两个人是否在同一个社交圈子,或者合并不同的社交圈子。
  • 图像分割:将图像中的像素根据某种相似性规则划分为不同的区域,通过并查集来合并相似的像素区域
;