并查集以及路径压缩

并查集以及路径压缩

一、概念

并查集是一种树型的数据结构,他的思想是用一个数组表示了整片森林(parent),树的根节点唯一标识了一个集合,我们只要找到了某个元素的的树根,就能确定它在哪个集合里。他有两个操作:

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询两个元素是否在同一个集合中。这个确定方法就是不断向上查找找到它的根节点,它可以被用来确定两个元素是否属于同一子集。

二、操作

每一个集合用一棵树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点, parents[x] 表示 x 的父节点。

2.1 初始化

并查集的重要思想在于,用集合中的一个元素代表集合。因为刚开始每个集合只有一个点,所以直接让本身作为父节点即可。parents[x] = x 是祖宗节点的一个标志,因为只要不是祖宗节点,parents[x] 存储的是 x 的父节点。

那么当前的parents数组就应该是

i12345
parents[i]12345

在这里插入图片描述

2.2 合并

当我们想让一个节点的集合加入另一个节点的集合时,使用合并操作,修改他们parents数组的值即可,例如我们想让2、3合并以及4、5合并,那么修改parents[3] = 2, parents[5] = 4

i12345
parents[i]12244

在这里插入图片描述

而此时我们希望4的集合再加入2的集合里,那么同理修改parents[4] = 2

i12345
parents[i]12224

在这里插入图片描述

2.3 查找

这个方法的是利用parents数组,不断向上寻找x的祖先,直到找到一个节点的parents就是他自己,即为该节点的最祖先节点。他的伪代码是这样的

while(parents[该节点]!=该节点)
{
	该节点 = parents[该节点]
}
例如拿上图来说,希望找到节点5的最祖先节点:
 1. 找到parents[5] = 4
 2. 找到parents[4] = 2
 3. 发现parents[2] = 2,那么返回节点2

2.4 路径压缩

上述的方法是并查集树林的最基础的表示方法,这个方法不会比链表法好,这是因为创建的树可能会严重不平衡,因此可以用路径压缩的方法优化。

路径压缩是一种在执行“查找”时扁平化树结构的方法。关键在于在路径上的每个节点都可以直接连接到根上;他们都有同样的表示方法。为了达到这样的效果,Find查找节点时,会依次改变该节点的所有祖先节点的引用到根节点。得到的树将更加扁平,为以后直接或者间接引用节点的操作加速。

在这里插入图片描述

三、代码实现

vector<int> parents;//并查集,存储每个节点的父节点/祖先节点

//初始化并查集数组,初始时令所有的节点的父节点都是自己
void initialparent(int nodenum)
{
	parents.resize(nodenum, -1);
	for (int i = 0; i < nodenum; i++)
	{
		parents[i] = i;
	}
}

//寻找node节点的最祖先的节点,同时对该节点的所有祖先做路径压缩
int find(int node)
{
	//寻找最祖先的节点
	int r = node;
	while (parents[r] != r)
	{
		r = parents[r];
	}
	int t = node;
	//压缩路径
	while (t != r)//t是从该节点node开始向上到达祖先节点r的所有节点
	{
		int temp = parents[t];
		parents[t] = r;
		t = temp;
	}
	return r;
}

//合并两个节点的集合
void merge(int x,int y)
{
	int r1 = find(x);
	int r2 = find(y);
	if (r1 == r2)
		return;
	if (parents[r1] > parents[r2]) {
		parents[r1] = r2;
	}
	else {
		parents[r2] = r1;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值