并查集(Union-Find)数据结构详解

文章目录

1. 什么是并查集?

并查集(Union-Find) 是一种用于管理 不相交集合(Disjoint Sets) 的数据结构,主要支持以下两种操作:

  • Find(u):查找元素 u 所属的集合(通常返回其根节点)。
  • Union(u, v):合并两个元素 uv 所在的集合。

并查集广泛应用于:

  • 图的连通性问题(如Kruskal算法求最小生成树)。
  • 动态连通性问题(如社交网络中的好友关系)。
  • 游戏开发(如像素连通性检测)。

2. 并查集的实现

(1)基本实现

初始时,每个元素独立构成一个集合,用数组 parent[] 存储父节点:

cpp 复制代码
vector<int> parent(n);
for (int i = 0; i < n; i++) {
    parent[i] = i; // 初始化,每个节点的父节点是自己
}
  • Find(u)(路径压缩优化):

    cpp 复制代码
    int find(int u) {
        if (parent[u] != u) {
            parent[u] = find(parent[u]); // 路径压缩
        }
        return parent[u];
    }
  • Union(u, v)(按秩合并优化):

    cpp 复制代码
    vector<int> rank(n, 0); // 记录树的深度
    bool unionSets(int u, int v) {
        int rootU = find(u);
        int rootV = find(v);
        if (rootU == rootV) return false; // 已经在同一集合
        if (rank[rootU] > rank[rootV]) {
            parent[rootV] = rootU; // 小树合并到大树
        } else if (rank[rootU] < rank[rootV]) {
            parent[rootU] = rootV;
        } else {
            parent[rootV] = rootU;
            rank[rootU]++; // 深度相同,合并后深度+1
        }
        return true;
    }

(2)优化策略

优化方法 作用 时间复杂度
路径压缩(Path Compression) 使 Find 操作接近 O ( 1 ) O(1) O(1) O ( α ( n ) ) O(α(n)) O(α(n))
按秩合并(Union by Rank) 避免树过高,保持平衡 O ( α ( n ) ) O(α(n)) O(α(n))

其中,α(n) 是 反阿克曼函数,增长极其缓慢,可以认为是常数时间。

3. 并查集的应用

(1)检测无向图的环

cpp 复制代码
bool hasCycle(vector<vector<int>>& edges, int n) {
    UnionFind uf(n);
    for (auto& edge : edges) {
        int u = edge[0], v = edge[1];
        if (!uf.unionSets(u, v)) {
            return true; // 已经连通,说明有环
        }
    }
    return false;
}

(2)Kruskal算法求最小生成树(MST)

⭐算法OJ⭐连接所有点的最小费用【最小生成树】(C++实现)Min Cost to Connect All Points

cpp 复制代码
int kruskalMST(vector<vector<int>>& edges, int n) {
    sort(edges.begin(), edges.end()); // 按权重排序
    UnionFind uf(n);
    int res = 0;
    for (auto& edge : edges) {
        int cost = edge[0], u = edge[1], v = edge[2];
        if (uf.unionSets(u, v)) {
            res += cost;
        }
    }
    return res;
}

(3)朋友圈问题

cpp 复制代码
int findCircleNum(vector<vector<int>>& isConnected) {
    int n = isConnected.size();
    UnionFind uf(n);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (isConnected[i][j]) {
                uf.unionSets(i, j);
            }
        }
    }
    int circles = 0;
    for (int i = 0; i < n; i++) {
        if (uf.find(i) == i) circles++; // 统计根节点数量
    }
    return circles;
}

4. 并查集的复杂度分析

操作 无优化 路径压缩 路径压缩 + 按秩合并
Find O ( n ) O(n) O(n) O ( α ( n ) ) O(α(n)) O(α(n)) O ( α ( n ) ) O(α(n)) O(α(n))
Union O ( n ) O(n) O(n) O ( α ( n ) ) O(α(n)) O(α(n)) O ( α ( n ) ) O(α(n)) O(α(n))

其中, α ( n ) α(n) α(n) 是 反阿克曼函数(Inverse Ackermann Function) ,在大多数实际应用中接近于 O ( 1 ) O(1) O(1)。

可以认为: α ( n ) α(n) α(n) 是 "阿克曼函数需要递归多少次才能超过 n"。由于阿克曼函数增长极快, α ( n ) α(n) α(n) 几乎不会超过 5(在现实计算中)

5. 总结

并查集 是一种高效管理 不相交集合 的数据结构。

  • 路径压缩 + 按秩合并 可以使其接近 O ( 1 ) O(1) O(1) 时间。
  • 典型应用:检测环、最小生成树、动态连通性问题。
相关推荐
什码情况4 小时前
回文时间 - 携程机试真题题解
数据结构·python·算法·华为od·机试
lwewan5 小时前
26考研——栈、队列和数组_数组和特殊矩阵(3)
数据结构·笔记·考研·算法
晚雾也有归处6 小时前
链表(C++)
数据结构·c++·链表
拾零吖6 小时前
枚举算法-day2
数据结构·算法·leetcode
已经成为了代码的形状6 小时前
关于交换并查集内元素的一些题的做法
数据结构·算法
課代表7 小时前
利用 Excel 函数随机抽取(附示例)
数据结构·excel
Non importa9 小时前
【初阶数据结构】线性表之双链表
c语言·开发语言·数据结构·c++·考研·链表·学习方法
ydm_ymz10 小时前
初阶8 list
c语言·开发语言·数据结构·c++·list
意疏12 小时前
【数据结构篇】算法征途:穿越时间复杂度与空间复杂度的迷雾森林
数据结构
愚戏师14 小时前
数据结构与算法分析:树与哈希表(一)
数据结构·算法·链表·深度优先·广度优先·宽度优先