1. 并查集基础概念与应用场景
并查集(Disjoint Set Union,简称DSU)是一种处理不相交集合合并与查询问题的树型数据结构。我第一次接触这个数据结构是在解决网络连通性问题时,当时需要判断数万个节点中任意两个是否属于同一连通区域。传统方法效率低下,而并查集仅用几十行代码就完美解决了问题。
并查集的核心操作可以概括为:
- Find(x):查找元素x所属集合的代表元素
- Union(x, y):合并包含x和y的两个集合
- MakeSet(x):创建一个仅含x的新集合
在实际工程中,并查集最常见的应用场景包括:
- 社交网络中的好友关系处理(判断两人是否属于同一朋友圈)
- 编译器中的寄存器分配优化
- 图像处理中的连通区域标记
- 游戏开发中的碰撞检测系统
- 网络路由中的最小生成树计算(Kruskal算法)
提示:并查集的英文别名Union-Find Data Structure直接体现了它的两个核心操作,这也是面试中经常被问到的术语。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 并查集的朴素实现与性能瓶颈
2.1 基础数据结构表示
每个集合用一棵树表示,节点保存父指针。根节点的父指针指向自己,作为集合的代表元素。初始状态下,每个元素自成一个集合:
python复制class DSU:
def __init__(self, n):
self.parent = [i for i in range(n)] # 初始化每个元素的父节点是自己
这种表示法的空间复杂度为O(n),n为元素数量。在我的实际项目中,通常会额外维护一个size数组来记录集合大小,这在某些优化策略中很有用。
2.2 朴素Find操作的实现
Find操作需要从给定节点出发,沿着父指针递归查找到根节点:
python复制def find(self, x):
if self.parent[x] == x:
return x
return self.find(self.parent[x])
这种实现最坏情况下(树退化成链表)时间复杂度为O(n)。我曾在一个包含10^5个元素的项目中,由于未优化Find操作导致程序超时,这个教训让我深刻认识到优化的重要性。
2.3 朴素Union操作的实现
Union操作需要先找到两个元素的根节点,然后将其中一个根节点的父指针指向另一个:
python复制def union(self, x, y):
x_root = self.find(x)
y_root = self.find(y)
if x_root != y_root:
self.parent[x_root] = y_root
这种简单合并可能导致树高度不断增加。在一次图像处理任务中,我观察到随着Union操作增多,Find操作耗时呈线性增长,这促使我研究优化策略。
3. Find操作的路径压缩优化
3.1 路径压缩的原理
路径压缩的核心思想是在Find操作过程中,将查询路径上的所有节点直接挂载到根节点下,使树更加扁
