9.6.1 ACM-ICPC 数据结构:并查集
并查集简介
并查集(Union-Find 或 Disjoint Set Union)是一种用于管理不相交集合的数据结构,主要支持两种操作:合并(Union) 和 查找(Find)。它在解决连通性问题、图论问题(如最小生成树的 Kruskal 算法)以及其他需要动态连通性维护的场景中有着广泛应用。
并查集的核心思想是通过树结构表示集合中的元素,并通过路径压缩和按秩合并等优化手段提升操作效率。本文将介绍并查集的基本概念、操作及优化方法,并结合实际例子进行说明。
并查集的基本操作
- 查找(Find):查找元素所属的集合。通过在树结构中查找元素的根节点,我们可以确定该元素所属的集合。
- 合并(Union):将两个不同的集合合并为一个集合。该操作将两个树的根节点连接起来,形成一个新的树。
示例
假设有以下几个集合:
- {1}
- {2}
- {3}
- {4}
执行 Union(1, 2)
后,集合变为 {1, 2} 和 {3}, {4}。此时如果查询 Find(1)
或 Find(2)
,返回的结果都应该是它们的公共根节点。
并查集的优化策略
在基本的并查集操作中,每次 Find
操作都需要遍历树,直到找到根节点,这在最坏情况下可能会退化为线性时间复杂度。为了提高效率,我们可以采用以下两种优化策略:
-
路径压缩(Path Compression): 在执行
Find
操作时,通过将路径上所有节点直接指向根节点,从而大幅减少后续操作的路径长度。路径压缩的作用是在进行查找时“压缩”树的高度,从而加速未来的查找操作。 -
按秩合并(Union by Rank): 在执行
Union
操作时,将较小的树合并到较大的树上,从而避免树的高度过大。这里的“秩”可以理解为树的高度或节点数量,通过按秩合并可以有效控制树的高度。
代码示例
以下是使用路径压缩和按秩合并优化的并查集实现:
class UnionFind {
public:
vector<int> parent, rank;
UnionFind(int n) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; i++) {
parent[i] = i;