通俗易懂的C++并查集实现

定义

并查集(Disjoint-Set)的本质是一个森林,即树的集合,但是不需要维护复杂的二叉树/N叉树结构。其使用场景一般用在集合的合并与查询,主要有3个基本操作:

  • find_root(x): 查找元素x的根结点,如果
  • join_union(x1, x2): 将x1与x2所在集合合并
  • is_union(x1,x2): 判断x1与x2是否在同一个集合里

举个例子,很好理解

初始的时候,每个元素都是一个单独的集合,此时find(x) == x, is_union(i,j) == false
figure 1
现在我们对元素1与元素2做join_union操作,即join_union(1,2), 则find(1) == find(2) == 1, is_union(1,2) == true
figure 2
再进行join_union(1,3), 则元素1,2,3均在一个集合里 is_union(1,2) == is_union(2,3) == is_union(1,3) == true
figure 3

具体实现

  • find_root(x)
    我们用一个哈希表存储每个节点的父节点,如果一个元素是一个单独的集合,则其父节点为自己。 查找一个元素的根结点的时候,我们只需要递归的查询当前节点的父节点,当父节点与当前节点是同一个节点时,递归终止。
    但当一个集合很大的时候,很可能会出现最坏的情况,find_root(x)的时间开销为O(N), 此时我们可以在find_root操作中加上一个优化操作,当获取到find_root(x1)的结果为x2后,我们把元素x1的父指针指向x2,以此降低树的高度。该方法叫路径压缩
    figure 4
	std::unordered_map<T, T> parent_;
	template <typename T>
	T find_root(const T& x){
   
		auto parent_it = this->parent_.find(x);
		if (parent_it == this->parent_.end()) {
   
			this->parent_[x] = x;
			return x;
		}
		return parent_it->second == x ? x : (this->parent_[x] = this->find_root(parent_it->second));
	}
  • join_union(x1, x2)
    将元素x1与x2所在的集合合并。首先获取x1与x2各自的根节点r1与r2,然后将其中一个根节点,比如r1,的父指针指向r2即可。这里有个优化点,就是r1与r2应该让哪个做父节点,哪个做子节点。如果不加优化的话,很可能会出现最坏的情况,树的高度等于集合的大小
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值