并查集(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) 时间。
  • 典型应用:检测环、最小生成树、动态连通性问题。
相关推荐
papership6 小时前
【入门级-数据结构-3、特殊树:完全二叉树的数组表示法】
数据结构·算法·链表
smj2302_796826526 小时前
解决leetcode第3911题.移除子数组元素后第k小偶数
数据结构·python·算法·leetcode
山甫aa6 小时前
差分数组 ----- 从零开始的数据结构
数据结构
早日退休!!!6 小时前
《数据结构选型指南》笔记
数据结构·数据库·oracle
丑八怪大丑7 小时前
Java数据结构与集合源码
数据结构
一个爱编程的人15 小时前
一个数是不是素数
数据结构·算法
忡黑梨15 小时前
eNSP_从直连到BGP全网互通
c语言·网络·数据结构·python·算法·网络安全
地球资源数据云16 小时前
1900-2023年中国物种分布点位矢量数据集
大数据·数据结构·数据库·数据仓库·人工智能
AI人工智能+电脑小能手17 小时前
【大白话说Java面试题】【Java基础篇】第20题:HashMap在计算index的时候,为什么要对数组长度做减1操作
java·开发语言·数据结构·后端·面试·哈希算法·hash-index
牢姐与蒯17 小时前
cpp数据结构之map
数据结构