并查集介绍
并查集是一种树形结构,常用于解决不相交集合的查询与合并问题,典型应用如 Kruskal 最小生成树算法。
要点
核心API:
- connected:判断两个节点是否属于同一个集合(是否连通);
- unionNodes:将两个节点划分到同一个集合中(连通)。
实现时,通常使用parent数组记录每个节点的父节点,当前森林中的连通分量数则用全局的count表示,在unionNodes时动态维护。
此外,为防止出现树退化成链表的极端情况,需要路径压缩(或平衡性优化)来保证树的高度为常量。采用路径压缩的技巧后,除初始化外,其余操作的平均复杂度均为 O(1)。
代码模板
class UF
{
private:
/* 连通分量数 */
int count;
/* 每个节点的父节点 */
int *parent;
public:
UF(int n)
{
count = n;
parent = new int[n];
for (int i = 0; i < n; i++)
parent[i] = i;
}
~UF()
{
delete[] parent;
}
void unionNodes(int u, int v)
{
int root_u = find(u);
int root_v = find(v);
if (root_u == root_v)
return;
parent[root_u] = root_v;
count--;
}
/* 路径压缩,返回根节点 */
int find(int u)
{
if (parent[u] != u)
{
parent[u] = find(parent[u]);
}
return parent[u];
}
bool connected(int u, int v)
{
return find(u) == find(v);
}
int getCount()
{
return count;
}
};
练习
Tips
- 网格图中,可能需要使用虚拟的哑节点简化实现过程;
- 二维坐标 (x, y) 映射到一维的 x * n + y(n为列数),方便套用以上模板;
- 作为一种技巧性的数据结构,大部分可使用并查集的题目直接DFS即可。
Leetcode相关题目
参考
[1] https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-03a72/bing-cha-j-323f3/
[2] https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-03a72/kruskal-zu-e6b5b/