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

【Algorithm】Union-Find简单介绍

文章目录

  • Union-Find
    • 1 基本概念
      • 1.1 `Find(x)` - 查询操作
      • 1.2 `Union(x, y)` - 合并操作
    • 2 并查集的结构和优化
      • 2.1 数据结构设计
      • 2.2 两大优化策略(关键)
        • 2.2.1 路径压缩(Path Compression)
        • 2.2.2 按秩合并(Union by Rank or Size)
    • 3 使用并查集的注意事项
    • 4 典型应用场景
      • 4.1 判断连通性
      • 4.2 等价类/合并集合
      • 4.3 检测环路(图中是否有环)
      • 4.4 岛屿问题/连通区域
      • 4.5 网络连接问题
    • 5 实现模板
    • 6 问题示例:合并等价字符集合(字典序最小)
    • 7 总结

Union-Find

1 基本概念

并查集是一种用于处理集合合并与查询的数据结构,主要用于解决:

  • 判断两个元素是否属于同一个集合
  • 合并两个集合
  • 图的连通性问题(如 Kruskal 最小生成树、岛屿数量、等价类问题)

核心思想:每个元素初始是一个独立的集合(自成一个树的根)。使用两个操作:

  1. find(x):查找元素 x 所在集合的代表元(根)
  2. union(x, y) / unite(x, y):将元素 x 和 y 所在的两个集合合并为一个

1.1 Find(x) - 查询操作

  • 找出元素 x 所在集合的代表元(也叫根节点、父节点)
  • 判断两个元素是否属于同一个集合:只需比较它们的代表元是否相同

1.2 Union(x, y) - 合并操作

  • 将元素 xy 所在的两个集合合并
  • 目的是把两个集合的元素归于同一个集合(也就是连通)

并查集的本质:将多个不相交的集合合并,并在查询时保持高效


2 并查集的结构和优化

2.1 数据结构设计

  • parent[i]:表示第 i 个元素的父节点(初始时每个元素是自己的父亲)

  • 常见扩展字段:

    • rank[i]:节点的秩(可以理解为树的高度或大小,用于优化合并)
    • size[i]:集合的大小(如果你需要追踪每个集合的元素个数)

2.2 两大优化策略(关键)

2.2.1 路径压缩(Path Compression)
  • 优化 find(x) 操作
  • 将 x 到根节点路径上的所有节点直接指向根,降低后续查找的复杂度
  • 时间复杂度近似 O(α(n)),α 是反阿克曼函数,几乎是常数
int find(int x) {if (parent[x] != x)parent[x] = find(parent[x]);return parent[x];
}
  • 每次查询时,将 x 的所有祖先直接挂到根节点,形成扁平结构
  • 减少下次查找路径长度
2.2.2 按秩合并(Union by Rank or Size)
  • 合并时,总是将“较矮”的树合并到“较高”的树,保持整体平衡,防止链式退化
void union(int x, int y) {int px = find(x), py = find(y);if (px == py) return;if (rank[px] < rank[py])parent[px] = py;else if (rank[px] > rank[py])parent[py] = px;else {parent[py] = px;rank[px]++;}
}

3 使用并查集的注意事项

注意事项说明
初始化每个元素一开始是自己的父节点(parent[i] = i
找代表元要用 find()不要直接比较 parent[x] == parent[y],必须比较 find(x) == find(y)
使用路径压缩提高查找效率,避免变成链表结构
合并要检查代表元避免重复合并或死循环
不适合有环结构查询并查集不能表示通用图(除非用于检测是否成环)
不支持高频动态插入删除并查集适合处理固定集合或批量问题,不适合频繁插入删除

4 典型应用场景

并查集广泛应用于以下场景:

4.1 判断连通性

  • 无向图中判断两个点是否连通
  • 例题:LeetCode 547. 省份数量(朋友圈)

4.2 等价类/合并集合

  • 把多个元素按关系合并为“集合组”
  • 例题:LeetCode 1061. 按字典序排列的最小等价字符串

4.3 检测环路(图中是否有环)

  • 并查集用于无向图的成环检测
  • 例题:Kruskal 最小生成树(MST)

4.4 岛屿问题/连通区域

  • 将二维网格中相邻的“陆地”用并查集合并,统计岛屿数
  • 例题:LeetCode 200. 岛屿数量

4.5 网络连接问题

  • 网络中节点是否连通、连接多少次才能连通
  • 例题:LeetCode 1319. 连通网络的操作次数

5 实现模板

class UnionFind {
private:vector<int> parent;vector<int> rank;  // 或者 sizepublic:UnionFind(int n) {parent.resize(n);rank.resize(n, 1);iota(parent.begin(), parent.end(), 0); // parent[i] = i}// 查找根节点,并进行路径压缩int find(int x) {if (parent[x] != x)parent[x] = find(parent[x]); // 路径压缩return parent[x];}// 合并两个集合void unite(int x, int y) {int px = find(x);int py = find(y);if (px == py) return;// 按秩合并if (rank[px] < rank[py]) {parent[px] = py;} else if (rank[px] > rank[py]) {parent[py] = px;} else {parent[py] = px;rank[px]++;}}// 判断两个元素是否在同一个集合bool connected(int x, int y) {return find(x) == find(y);}
};

6 问题示例:合并等价字符集合(字典序最小)

当我们想用并查集维护字符集合时,可以做如下改造:

  • parent[26]:表示字符 ‘a’ 到 ‘z’ 的父节点
  • 合并时总是把字典序较小的字符作为根,这样找出的代表字符就是该等价类的最小字母
class Solution {
public:string smallestEquivalentString(string s1, string s2, string baseStr) {vector<int> parent(26);iota(parent.begin(), parent.end(), 0); // a-z 的并查集// 路径压缩查找function<int(int)> find = [&](int x) {if (parent[x] != x)parent[x] = find(parent[x]);return parent[x];};// 合并两个字符等价类,保留字典序较小的作为代表auto unite = [&](int x, int y) {int px = find(x);int py = find(y);if (px == py) return;if (px < py)parent[py] = px;elseparent[px] = py;};for (int i = 0; i < s1.length(); ++i) {unite(s1[i] - 'a', s2[i] - 'a');}string res;for (char c : baseStr) {res += (char)(find(c - 'a') + 'a');}return res;}
};

7 总结

问题特征是否适合使用并查集
不相交集合合并非常适合(核心用途)
判断两个元素是否属于同一集合非常高效
图的连通性/聚类问题适合
频繁增删元素不适合,建议用更复杂的数据结构
要维护复杂属性(如路径)不适合
操作说明时间复杂度
find(x)查找 x 所在集合的代表元O(α(n))
unite(x,y)合并两个集合O(α(n))
connected(x,y)判断是否在同一集合O(α(n))

由于路径压缩和按秩合并优化,几乎所有操作都是近乎常数时间。

相关文章:

  • Filebeat收集nginx日志到elasticsearch,最终在kibana做展示(二)
  • JAVA之 Lambda
  • 算法训练第九天
  • docker快速部署OS web中间件 数据库 编程应用
  • 第14节 Node.js 全局对象
  • 【推荐算法】WideDeep推荐模型:融合记忆与泛化的智能推荐引擎
  • 37.第二阶段x64游戏实战-封包-寻找Socket套接字
  • Oracle杀进程注意事项
  • oracle数据恢复—oracle数据库执行truncate命令后的怎么恢复数据?
  • Java并发编程实战 Day 9:锁优化技术
  • C语言 — 编译和链接
  • 【杂谈】-吉卜力化(Ghiblified ) AI 图像:艺术与隐私的交织
  • PDF 转 HTML5 —— HTML5 填充图形不支持 Even-Odd 奇偶规则?(第二部分)
  • PyCharm中运行.py脚本程序
  • chrome使用手机调试触屏web
  • 大模型学习
  • ROS2中实现导航仿真
  • Hive SQL常见操作
  • 云服务器宕机或自动重启怎么办
  • TikTok养号指南:从0到1打造防限流账号的实战策略
  • 长沙企业官方网站建设/上优化seo
  • 程序员做网站给女朋友/长尾关键词排名推广
  • 荔湾区做网站公司/广州外包网络推广公司
  • 做微信公众号的网站有哪些内容/百度怎么推广自己的网站
  • 福州做网站建设/上海网站建设方案
  • 网站开发经理具备什么知识/软件推广平台有哪些