概念(Disjoint set)
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。
并查集的思想是用一个数组表示了整片森林(parent),树的根节点唯一标识了一个集合,我们只要找到了某个元素的的树根,就能确定它在哪个集合里。
用处
最大作用是检查一个图存不存在一个环
图形表示
代码实现
构建并查集
初始化
#include<stdio.h>
# define VERTICES 6
void initialise(int parent[]){
int i;
for (i = 0; i < VERTICES;i++){
parent[i] = -1;
}
}
int main(){
int parent[VERTICES] = {0};
int edges[6][2]={{0,1},{1,2},{1,3},{2,4},{3,4},{2,5}};
initialise(parent);
int i;
for (i = 0; i < 6; i++){
int x = edges[i][0];
int y = edges[i][i];
if(union_vertices(x,y,parent) == 0) {
printf("Cycle detected!\n");
}
}
printf("No Cycle found.\n");
return 0;
}
找到根节点
// x是顶点
int find_root(int x,int parent[]) {
int x_root = x;
while(parent[x_root] != -1){
x_root = parent[x_root];
}
return x_root;
}
合并集合
//x和y是顶点
// 1 - uniom sucessfully合并成功,0 - failed合并失败(如果要合并的两个节点在同一个集合内,则合并失败)
int union_vertices(int x,int y,int parent[]) {
int x_root = find_root(x,parent);
int y_root = find_root(y,parent);
//找到的两个根节点相同,合并失败
if (x_root == y_root) {
return 0;
}
//合并成功
else {
parent[x_root] = y_root;
return 1;
}
}
缺点
如果节点数比较多,超过10,000个节点,(0,1),(1,2),(2,3),(3,4),…,所有路径连成了一条链,查找过程中会有lon(n)的复杂度,需要进一步进行优化。
代码优化(路径压缩)
初始化
#include<stdio.h>
# define VERTICES 6
void initialise(int parent[]){
int i;
for (i = 0; i < VERTICES;i++){
parent[i] = -1;
rank[i] = 0;
}
}
int main(){
int parent[VERTICES] = {0};
int rank[VERTICES] = {0};
int edges[6][2]={{0,1},{1,2},{1,3},{2,4},{3,4},{2,5}};
initialise(parent,rank);
int i;
for (i = 0; i < 6; i++){
int x = edges[i][0];
int y = edges[i][i];
if(union_vertices(x,y,parent,rank) == 0) {
printf("Cycle detected!\n");
}
}
printf("No Cycle found.\n");
return 0;
}
找到根节点
// x是顶点
int find_root(int x,int parent[]) {
int x_root = x;
while(parent[x_root] != -1){
x_root = parent[x_root];
}
return x_root;
}
合并集合
//x和y是顶点
// 1 - uniom sucessfully合并成功,0 - failed合并失败(如果要合并的两个节点在同一个集合内,则合并失败)
int union_vertices(int x,int y,int parent[],int rank[]) {
int x_root = find_root(x,parent);
int y_root = find_root(y,parent);
//找到的两个根节点相同,合并失败
if (x_root == y_root) {
return 0;
}
//合并成功
else {
//parent[x_root] = y_root;
if(rank[x_root] > rank[y_root]){
parent[y_root] = x_root;
}
else if(rank[x_root] < rank[y_root]){
parent[x_root] = y_root;
}
else {
parent[x_root] = y_root;
rank[y]++;
}
return 1;
}
}