up主讲的非常详细,推荐看视频
并查集可以用来判断一个图是否有环
注意:下面的点是从0开始构造树,有的题目是从1开始构造图了,这样的话parent数组大小就会变
重点是找到根节点和连接两个结点:
该代码只是强硬的将x的根节点设置成y,并没有考虑性能上的优化,可能树的高度非常高.
#include<stdio.h>
#include<stdlib.h>
//设置顶点数量
#define VERTICES 6
//初始化parent数组,让其设置为-1
void initialise(int parent[]){
int i;
for(i=0;i<VERTICES;i++){
parent[i]=-1;
}
}
// 找根节点
int find_root(int x, int parent[]){
//假设根节点是自己
int x_root = x;
//如果根节点不是自己,一直找到根节点
while(parent[x_root] != -1){
x_root = parent[x_root];
}
//返回根节点
return x_root;
}
//合并两个结点,如果两个结点没有共同的根节点,就可以成功合并返回1,否则返回0
/* 1 - union successfully, 0 -failed*/
int union_vertices(int x, int y,int parent[]){
//找到x,y的根节点
int x_root=find_root(x,parent);
int y_root=find_root(y,parent);
//比较根节点是否相同 ,相同返回0
if(x_root == y_root){
return 0;
}
// 根节点不同进行合并,然后返回1
else{
parent[x_root] = y_root;
return 1;
}
}
int main(void){
int parent[VERTICES] = {0};
int edges[6][2] = {
{0,1},{1,2},{1,3},
{2,4},{3,4},{2,5}
};
//初始化parent数组
initialise(parent);
int i;
//合并结点,看是否有环
for(i=0;i<6;i++){
int x = edges[i][0];
int y = edges[i][1];
//有环的话就会打印有环,从而退出程序
if(union_vertices(x,y,parent)==0){
printf("Cycle detected!\n");
exit(0);
}
}
//没环的话打印没环
printf("No cycles found\n");
return 0;
}
优化代码,让树的高度尽量低
如果那个树高,就让他当做另一个树的根节点,这样可以提高性能
#include<stdio.h>
#include<stdlib.h>
//设置顶点数量
#define VERTICES 6
//初始化parent数组,让其设置为-1
void initialise(int parent[], int rank[]){
int i;
for(i=0;i<VERTICES;i++){
parent[i]=-1;
//初始高度设置为0
rank[i]=0;
}
}
// 找根节点
int find_root(int x, int parent[]){
//假设根节点是自己
int x_root = x;
//如果根节点不是自己,一直找到根节点
while(parent[x_root] != -1){
x_root = parent[x_root];
}
//返回根节点
return x_root;
}
//合并两个结点,如果两个结点没有共同的根节点,就可以成功合并返回1,否则返回0
/* 1 - union successfully, 0 -failed*/
int union_vertices(int x, int y,int parent[],int rank[]){
//找到x,y的根节点
int x_root=find_root(x,parent);
int y_root=find_root(y,parent);
//比较根节点是否相同 ,相同返回0
if(x_root == y_root){
return 0;
}
// 根节点不同进行合并,然后返回1
else{
if(rank[x_root]>rank[y_root]){
parent[y_root] = x_root;
}
else if(rank[y_root]>rank[x_root]){
parent[x_root] = y_root;
}
//高度一致的时候
else{
parent[x_root] = y_root;
rank[y_root]++;
}
}
return 1;
}
int main(void){
int parent[VERTICES] = {0};
int rank[VERTICES]={0};
int edges[6][2] = {
{0,1},{1,2},{1,3},
{2,4},{3,4},{2,5}
};
//初始化parent数组 和rank数组
initialise(parent,rank);
int i;
//合并结点,看是否有环
for(i=0;i<6;i++){
int x = edges[i][0];
int y = edges[i][1];
//有环的话就会打印有环,从而退出程序
if(union_vertices(x,y,parent,rank)==0){
printf("Cycle detected!\n");
exit(0);
}
}
//没环的话打印没环
printf("No cycles found\n");
return 0;
}