并查集基础知识

1.概念:

将编号分别为1…N的N个对象划分为不相交集合,

在每个集合中,选择其中某个元素代表所在集合。

常见两种操作:

两个集合

找某元素属于哪个集合,判断两个元素是否属于同一个集合。

是一种树形的数据结构,又称“不相交集合”,用于处理一些不相交集合的合并及查询问题。

2.数学模型:

并查集的数学模型是若干不相交集合的集合S={A,B,C,...},它支持以下的运算:     (1)INITIAL(A,x):构造一个取名为A的集合,它只包含一个元素x;  

  (2)MERGE(A,B):将集合A和B合并,其结果取名为A或B;  

  (3)FIND(x):找出元素x的所在集合,并返回该集合的名字。

3.算法实现:

 1)用编号最小的元素标记每个集合;

set[x] 即元素x所在集合的最小元素

此时并查操作:

//查找任意x所在集合,而集合以最小元素为代表

int find(x){
 return set[x];
}

时间复杂度:O(1);

//合并两个集合,即让代表元素大的集合的所有元素都小元素代表为代表

void Merge(a,b){
int i=min(set[a],set[b]);
int j=max(set[a],set[b]);
for(int k=1;k<=n;k++){
 if(set[k]==j) set[k]=i;
}
}
int min(int a,int b){
return a>b?b:a;
}
int max(int a,int b){
 return a>b?a:b;
}

时间复杂度O(n);

用树形结构改进

2)每个集合用一棵“有根树”表示

定义数组 fa[1..n]     fa[i] = i , 则i表示本集合,并是集合对应树的根

fa[i] = j, j≠i, 则 j 是 i 的父节点.

查找:

int find(x){
   while(father[x]!=x) x=father[x];   //找到根节点
   return x;
}

 合并:

void merge(int x,int y){
  int fx=find(x),fy=find(y);
   if(fx==fy) return;
    fa[fx]=fy;
}

最坏情况 O(N);

再次改进,避免最坏情况。  //每次合并,都合并在一条线上。

3)路径压缩,引入秩合并集合

考虑每次查找时 修改路径上的所有节点,使其指向根节点。  //路径压缩

非递归:

int find(int x){
 int r=x;  //保存要查找节点
 while(father[r]!=r) r=father[r]; //找到根节点
 while(father[x]!=x){
   int f=father[x]; //保存此节点的父节点
   fa[x]=r; //更改父节点,使其指向根节点
   x=f;
}
return r;
}

递归:

int find(int x){
   if(x!=father[x]) father[x]=find(father[x]); //递归调用
   return father[x];
}

合并两个集合时,为了避免树一直竖向增长,按秩合并。

增加一个数组,初始为0保存每个集合的秩

思路: 若两个集合秩相等,则任选一个根节点作为父节点,秩加1;

  秩不同时,较小秩的集合指向较大秩的集合

void make_set(int x){   //初始化集合
	father[x]=x;   //根节点 
	R[x]=0; //秩大小,子树长度 
}
void merge(int x,int y){ 
   int tx=find(x),ty=find(y);   //找到根节点,即所在集合
   if(tx==ty) return; //在同一个集合
   if(R[tx]<R[ty]{
      father[tx]=ty;
   }
   else{
     if(R[tx]==R[ty]) R[tx++];
      father[ty]=tx;
   }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值