并查集模板

普通并查集:

#define MAX_SIZE 100005  
int pa[MAX_SIZE];        //存储有向图的边

void init()     //初始化	该函数可以根据具体情况保存和初始化需要的内容  
{  
	for(int i = 0; i < MAX_SIZE; i++)  
	{  
		pa[i] = i;  
	} 
}  

int findset(int a)	//不带路劲压缩  
{  
	while(pa[a] != a)  
	{  
		a = pa[a];  
	}  
	return a;  
}  

void union_nodes(int a, int b)      //集合合并  
{  
	int a1 = findset(a);  
	int b1 = findset(b);
	if(a1 != b1)		//这个判定条件可选,主要是为了防止findset路径压缩的时候出现死循环
	{
		pa[a1] = b1;		//如果存的是有向图,并且做题时集合中元素的顺序很重要,不能忽略,那么这里应该用"pa[a] = b;" 
	}
} 


 

带路径压缩的的findset函数:

1.while版本

int findset(int v)      //找元素所在集合的代表元(因为用了路径压缩,路径压缩的主要目的是为了尽快的确定元素所在的集合)  
{  
	int t1,t2=v;  
	while(v!=pa[v])  
		v=pa[v];  
	while(t2!=pa[t2])        //这里优化的思路还是路径压缩(进一步的在查找函数执行的过程中压缩路径),很神奇!  
	{  
		t1=pa[t2];  
		pa[t2]=v;  
		t2=t1;  
	}  
	return v;  
} 


2.递归版本

int findset(int x)  
{  
	if(pa[x] != x)  
	{         
		int root = findset(pa[x]);   
		return pa[x] = root;  
	}  
	else  
	{  
		return x;  
	}  
}  


 

个人经验表明在递归版本不栈溢出的情况下,递归版本和循环版本的效率并没有太大差别,并且对于带路径压缩的并查集,基本上不会发生“递归栈溢出”。


另外,union_nodes函数还可以可以采用启发式合并,思路就是把深度较小的那棵子树并到深度较大的那棵子树上,不过一般情况下路径压缩就够用了。
听人说并查集还可以“离散化”,个人从字面上理解应该是指用map、hash来保存每个节点,从而当节点分布比较稀疏的时候,可以比普通并查集更快的完成初始化等工作(待商榷)。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值