数据结构之并查集

并查集可以用来维护集合之间的关系(合并两个集合、判断两个元素是否属于一个集合等),是一种较为高效的数据结构,时间复杂度接近 O(1)。

在并查集中,我们把每个集合看做是一棵树,把每一个元素看做树中的一个节点,每棵树有一个表示编号的树根;

合并两个集合就将一棵树的树根连接到另一棵树的树根上;

查询两个元素是否处于一个集合中就查看两个元素的树根是否相同。

并查集的实现:

p[i] 表示 i 元素的父节点的编号,初始时通常 p[i] = i,代表 i 元素的父节点编号为 i;

find(a) 操作返回 a 元素的根节点编号;

合并操作:

假设合并1号元素和2号元素,p[find(a)]=p[find(2)],表示将1号元素的根节点连接到2号元素的根节点上;

判断两个元素是否在一个集合中:

判断两个元素的树根是否相同,find(a) == find(b);

统计集合中元素数量

记录每个树根下有多少元素,当合并1号元素和2号元素时,cnt[find(2)] += cnt[find(1)],表示2号树根的元素个数加上1号树根下的元素个数;

路径压缩操作:

如果按照上述方式的合并操作,数的高度会不断变大,那么时间复杂度是线性的;我们使用路径压缩操作,即将树上的所有元素直接连接到树根,路径压缩操作包含在 find() 函数中。

图示:

 

代码模板如下:

//初始化并查集
for (int i = 1; i < n; i++)p[i] = i;

//查找根节点并且路径压缩,返回根节点
int find(int x) {
	if (x != p[x])p[x] = find(p[x]);
	return p[x];
}

//合并集合a,b
p[find[a]] = find(b);
//合并a,b时将元素个数也合并
if (find(a) != find(b)) {
	cnt[find(b)] += cnt[find(a)];
}

//判断是否在一个集合中
if (find(a) == find(b))return true;

find操作的解释:
查找树根时,递归向上查找,最后返回树根的编号。在回溯的过程中进行路径压缩,将树上的每一层元素都直接连接到树根。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值