【算法基础】并查集(傻瓜式教学)

一.概念

       并查集(Disjoint Set),在一些有N个元素的集合应用问题中,通常应用于判断一个图里是否有环或者两个结点是否在同一个集合里。

二.解析

我们先判断三个结点是否成环的条件
其实很简单,假设有两个点连在一起,即两个点在同一个集合里,这时候第三个点如果和两个之间都有边的时候就成环了。
反过来理解,遍历到某条边,如果两个端点都在同一个集合里,那么图中就有环

首先对于这么一个图,我们可以随机遍历图的每一条边
在这里插入图片描述
我们可以设 parent[i] = x 表示结点 i 的父节点为 x
并且初始化 parent [ i ] = i
这样一开始parent数组为
在这里插入图片描述

然后就遍历每条边,记录每个结点的父节点
但是要注意的是,当我们随机遍历的时候,我们可能会产生多个树,如果遍历到最后有两个树要合并时,我们一般都是通过链接两个树的的根节点,如下图是两个树(红边是已选的,黑边是还未选的)
在这里插入图片描述

遍历到(1,3)这条边时,我们发现这两个树应该要合并为一个树,此时我们不是记录parent[3]=1。而是找出他们的根节点,分别为0,3,然后连接他们,即parent[3]=0,如下图
在这里插入图片描述
然后遍历(2,4)边,因为2的根节点为0,4的根节点也是0,所以2和4之间成环。找到环之后就不用继续往下遍历了
但是这种算法有一个缺陷,如下图
在这里插入图片描述
此时,两个结点间要判断成环的成本非常大,如果要判断0和5之间是否成环需要遍历5个结点才能知道。有两个几点之间如果n个结点就需要n个结点。此时并查集算法的时间复杂度就比较高了,达到了O(n)
那么这时候,是否有一个O(log2)的算法存在呢?
当然是有的啦
那就是——路径压缩

三.优化

还是以这张图为例
在这里插入图片描述
第一步,遍历(0,1)得到下图
在这里插入图片描述
遍历(1,2)边,此时因为parent[2]=1,parent[1]=0,我们可以令parent[2]=parent[1]
简单来说,a是b的属下,c是b的属下,那么c也是a的属下了。如下图
在这里插入图片描述
以此类推,最后能得到
在这里插入图片描述
这样,我们找0和5之间是否有环的代价就大大降低了

四.代码

int find(int x)//找出x结点的根节点
{
	if(x==parent[x]) {//找到根节点
		return x;
	} else {
		parent[x]=find(parent[x]);//路径压缩
		return parent[x];
	}
}

五.总结

其实并查集这个算法我老早就接触了,但是今天才把他写出来,不过,写出思路还是和单纯的用这代码不一样啊。
如果有意见的话,欢迎在评论区指出来哦QAQ

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值