令人头疼的并查集

刚开始接触就对这迷迷糊糊的,一直搞不懂,后来发现用处还不少,不得不从头来过啊!
先来个高级定义:并查集是一种高级的数据结构,能用于处理不相交集合的合并及查询。求最小生成树、亲戚关系的判定、最小公共祖先等都要用到。

并查集的使用主要有三步:定义数组并初始化、查找元素的根节点、合并不相交的集合。

1、定义数组并初始化:

int per[1001],n;//根据具体情况定义 
for(int i=1;i<=n;i++){//i从1开始 
	per[i]=i;//初始化为自身 
}
2、接下来是查找元素的根节点,判断有几棵树:

int findx(int x){
	int r=x;//局部变量 
   	while(per[r] !=r)//根节点满足的条件为per[r]==r 
        r=per[r];//(*) 
   	return r;//返回根节点 
}
(*)那条语句一直很懵逼,当初一直在想为什么不直接用个if语句,多省事!后来想了想,还是用循环比较靠谱,因为当r=pre[r]时,pre[r]=pre[pre[r]] 抓狂,慢慢体会吧。。。

3、下一步就是树与树之间的合并了:

void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)//如果x,y的根节点不相等 
		pre[fx]=fy;//x,y中以y为根节点,也可写成pre[fy]=fx,以x为根节点;
}
好不容易理解了一点点儿,又出来一个路径压缩。。。

官方的说法:在使用并查集查找时,如果查找次数很多,那么上述的2查找方法可能就会超时,所以需要代码优化,即路径压缩(就是在每次查找时,令查找路径上的每个节点都直接指向根节点,技术有限,图就不配了,问度娘)。方法有两种,细细道来。。

(1)、递归:

int find(int x){
    if (x != parent[x]){
        parent[x] = find(parent[x]);//回溯时的压缩路径
    }//从x结点搜索到祖先结点所经过的结点都指向该祖先结点
    return parent[x];
}
但是采用递归的方式压缩路径时,有可能会造成栈溢出(其实我也不知道是为啥),下面说方法二:

int find(int x){
    int k,j,r;
    r=x;
    while(r!=per[r])//查找根节点
    	r=per[r];//找到根节点,用r记录下
    k=x;        
    while(k!=r){//非递归路径压缩操作
        j=per[k];//用j暂存per[k]的父节点
        per[k]=r;//per[x]指向根节点
        k=j;//k移到父节点
    }
    return r;//返回根节点的值            

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值