并查集
可以快速确定两个元素是否属于同一个子集
主要方法:find(查找元素的根元素),union(合并两个子集)
朴素代码:
int find(int x)
{
return parent[x] == x ? x : find(parent[x]);
}
void union(int x1, int x2)
{
parent[find(x1)] = find(x2);
}
当某个子集为例如:4->3->2->1->0时,对于每次遍历都是对集合的遍历,所以需要路径压缩:
// 在find的过程中进行路径压缩,非递归路径压缩
int find(int root)
{
int son, tmp;
son = root;
while(root != pre[root]){
root = pre[root];
}
// 将该树枝上的节点都直接接到root上
while(son != root){
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root;
}
void union(int x1, int x2)
{
int r1, r2;
r1 = find(x1);
r2 = find(x2);
if(r1 != r2){
pre[r1] = r2;
}
}
另外一个思路是按秩合并,将秩小的合并到秩大的子集:
// 递归的路径压缩
int find(int x)
{
return x == parent[x] ? x : (parent[x] = find(parent[x]));
}
void union(int x1, int x2)
{
int f1 = find(x1);
int f2 = find(x2);
if (rank[f1] > rank[f2]){
parent[f2] = f1;
} else{
parent[f1] = f2;
if(rank[f1] == rank[f2]){
++rank[f2];
}
}
}