并查集,听大佬说是最小生成树的基础。不过现在还是按部就班,顺着学。
个人理解,仅供参考:
// 算法4 第一章第五节并查集的实现
// 路径压缩:将最顶部的根下所有子节点的值更新为最顶部的根的值,优化找根时间复杂度
// 加权:仅将小树连到大树,同样也是优化找根时间复杂度
#include <stdio.h>
const int N = 1e5;
int id[N], sz[N]; // sz数组用来保存数的大小
// 初始化
void init(){
for(int i=0; i<N; i++){
id[i] = i; // 默认所有点都是自己的根
sz[i] = 1; // 默认所有点组成的树的大小为 1
}
}
// 路径压缩找根
int find(int p){
if(p != id[p]){ // 如果当前点不是自己的根
id[p] = find(id[p]); // 找到根,递归退出,同时将上层的点的根更新为最顶部的根
}
return id[p]; // 这里不能 return p,路径压缩后 p 只是充当下标
}
// 连接p、q
void union_pq(int p, int q){
int pRoot = find(p); // 找到 p 的根
int qRoot = find(q);// 找到 q 的根
if(pRoot == qRoot){ // 两根相同则什么也不做
return ;
}else{
if(sz[pRoot] < sz[qRoot]){ // 如果 p 的树大小小于 q 的树的大小
id[pRoot] = qRoot; // 将 p 树连接到 q树
sz[qRoot] += sz[pRoot]; // q 树的节点个数增加为 p 树的大小
}else{// 同理
id[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}
}
}
// 如果两个结点连在一起,表明两个结点的根相等
int connected(int p, int q){
return find(p) == find(q);
}
int main(){
init();
union_pq(1, 2);
union_pq(3, 2);
union_pq(4, 2);
union_pq(4, 6);
union_pq(4, 7);
int cnt = 0;
for(int i=0; i<8; i++){
printf("%d ", id[i]);
if(id[i] == i){
cnt++;
}
}
printf("\n%d %d %d\n", cnt, connected(1, 6), connected(0, 1));
return 0;
}