当前位置: 首页 > news >正文

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

文章目录

  • 1. 什么是并查集?
  • 2. 并查集的实现
    • (1)基本实现
    • (2)优化策略
  • 3. 并查集的应用
    • (1)检测无向图的环
    • (2)Kruskal算法求最小生成树(MST)
    • (3)朋友圈问题
  • 4. 并查集的复杂度分析
  • 5. 总结

1. 什么是并查集?

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

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

并查集广泛应用于:

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

2. 并查集的实现

(1)基本实现

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

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

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

    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)检测无向图的环

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

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)朋友圈问题

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) 时间。
  • 典型应用:检测环、最小生成树、动态连通性问题。

相关文章:

  • Realsense-D400 系列手动曝光控制
  • 【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置
  • 质量工程:数字化转型时代的质量体系重构
  • 分布式锁,rediss,redisson,看门狗,可重入,可重试
  • ArcGIS 10.8.1之后发布栅格数据的MapServer 动态工作空间 替换数据源渲染问题
  • 基于Spring AI开发本地Jenkins MCP Server服务
  • JAVA中synchronized重量级锁加锁和释放锁的机制
  • Golang中间件的原理与实现
  • Linux 配置NFS服务器
  • Edge浏览器快速开启IE模式
  • MySQL 锁机制全面解析:乐观锁与悲观锁实现及深度剖析
  • ubuntu 2204键盘按键映射修改
  • DataGear 5.3.0 制作支持导出表格数据的数据可视化看板
  • OceanBase的闪回查询功能实践
  • IP数据报报文格式
  • 英伟达「虚拟轨道+AI调度」专利:开启自动驾驶3.0时代的隐形革命
  • 离散的数据及参数适合用什么算法做模型
  • vscode_拼写关闭
  • 从 WPF 到 MAUI:跨平台 UI 开发的进化之路
  • C++使用do {} while(false)的好处
  • 金融政策支持稳市场稳预期发布会即将召开,潘功胜、李云泽、吴清将出席
  • 上海乐高乐园明天正式开售年卡,下月开启试运营
  • 市场监管总局通报民用“三表”专项检查结果
  • 禅定佛的微笑,从樊锦诗提到过的那尊说起
  • 同路人才是真朋友——驻南苏丹使馆援助东赤道州人道主义物资交接仪式侧记
  • 海港通报颜骏凌伤停两至三周,国足面临门将伤病危机