接口的主要内容如下:
1、并查集初始化
2、合并:合并两棵树
3、查找:找某一节点所在树的根节点
4、连通性判断:判断两个节点是否连通,实质是判断其根节点是否相同
5、路径压缩:降低树的高度,进而降低查找的复杂度
6、连通分量个数统计
7、平衡性:使用size统计每棵树的节点数量,在合并的时候,总是让重量较小的树合并到重量较大的树的下方(即小树的根节点指向大树的根节点),避免树的高度变得不平衡。
#include <vector>
using namespace std;
// 并查集
class UnionFind
{
private:
int count; // 并查集中连通分量的个数
vector<int> size; // 存储树的"重量",用于在两颗树合并时,平衡树的高度
vector<int> parent; // 存储节点
public:
// 并查集初始化,开始时每个节点都是独立的
UnionFind(int n)
{
this->count = n;
parent.resize(n);
size.resize(n);
for (int i = 0; i < n; ++i)
{
parent[i] = i;
size[i] = 1;
}
}
// 返回当前集合中连通分量的个数
int count()
{
return this->count;
}
// 查找某个连通分量的根节点
int findRoot(int x)
{
while (parent[x] != x)
{
parent[x] = parent[parent[x]]; // 路径压缩
x = parent[x];
}
return x;
}
// 判断两个分量是否连通
bool connected(int p, int q)
{
int root_p = findRoot(p);
int root_q = findRoot(q);
return root_p == root_q;
}
// 合并两个集合
void UnionSet(int p, int q)
{
int root_p = findRoot(p);
int root_q = findRoot(q);
if (root_p == root_q) return;
if (size[root_p] > size[root_q])
{
parent[root_q] = root_p;
size[root_p] += size[root_q];
}
else
{
parent[root_p] = root_q;
size[root_q] += size[root_p];
}
this->count--;
}
};
谢谢阅读。