并查集

并查集(Union-find set),从字面上来看就是支持合并(union),查找(find) 的集合嘛。下面我们来学习一下这种数据结构

 并查集的精髓(即它的三种操作,结合实现代码模板进行理解):

1、Make_Set(x) 把每一个元素初始化为一个集合

初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。

2、Find_Set(x) 查找一个元素所在的集合

查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。
判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。
合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图

3、Union(x,y) 合并x,y所在的两个集合

合并两个不相交集合操作很简单:
利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。如图

Make_Set(x)就不多解释了,直接看代码

for(int i=1;i<=n;i++)

parent[i]=i;

下面看看并查集的核心Find_Set(x),其实这个操作并不只是简单的查找祖先的操作还有路径压缩的操作,以下图为例


假设我们在查找a的祖先,找到了d,而b,c,的祖先都是d,但是我们可能下一次要查找b的祖先,但是依然要从b往上面递归,显然次数多了,时间就多了,其实我们在之前查找a的祖先的时候,已经知道了b的祖先是d,这时候便有了我们的路径压缩操作。

看一下查找的一些操作

这是朴素查找的代码,适合数据量不大的情况:
int findx(int x)
{
int r=x;
while(parent[r] !=r)
r=parent[r];
return r;
}

下面是采用路径压缩的方法查找元素:

int find(int x) //查找x元素所在的集合,回溯时压缩路径
{
if (x != parent[x])
{
parent[x] = find(parent[x]); //回溯时的压缩路径
} //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
return parent[x];
}

上面是一采用递归的方式压缩路径, 但是,递归压缩路径可能会造成溢出栈,下面我们说一下非递归方式进行的路径压缩:

int find(int x)
{
int   r,tem;
r = x;
while(r != parent[r]) //查找跟节点
r = parent[r]; //找到跟节点,用r记录下 
while(x != r) //非递归路径压缩操作
{
  
  tem=parent[x];
  parent[x]=r;  
  x=tem;  
}
return x; //返回根节点的值 
}
最后看看合并的操作



void Unionset(int x,int y)
{
    int x1 = Find(x),y1 = Find(y);
    if(x1>y1) parent[x1] = y1;
    else parent[y1] = x1;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值