C++并查集优化实现

1.并查集

并查集示意图

  1. 有若干个样本a、b、c、d…类型假设是V
  2. 在并查集中一开始认为每个样本都在单独的集合里
  3. 用户可以在任何时候调用如下两个方法 :
    boolean isSameSet(V x, V y) : 查询样本x和样本y是否属于一个集合
    void union(V x, V y) : 把x和y各自所在集合的所有样本合并成一个集合
  4. isSameSet和union方法的代价越低越好
  5. 并查集有两个基本操作:
    Find: 查找元素所属子集
    Union:合并两个子集为一个新的集合

2.C++实现(未优化版本)

#include <vector>
using namespace std;
class UnionFind
{
private:
	vector<int> parent;
	int sets;
public:
	UnionFind(int max_size) : parent(vector<int>(max_size))
	{
		// 初始化每一个元素的父亲节点都为自身
		for(int i = 0;i < max_size;i++)
		{
			parent[i] = i;
		}
	}
	
	int find(int x)
	{
		return parent[x] == x ? x : find(parent[x]);
	}
	
	void union(int i, int j)
    {
        parent[find(i)] = find(j);
        sets--;//更新所含集合数目
    }
    
	// 判断两个元素是否属于同一个集合
    bool isSameSet(int i, int j)
    {
        return find(i) == find(j);
    }
   	int sets() {
		return sets;
	}
};


3.C++实现(优化版本)

采用“路径压缩”与“按秩合并”优化的并查集

  • “按秩合并”。实际上就是在合并两棵树时,将高度较小的树合并到高度较大的树上。
  • “路径压缩”。在执行find的过程中,将路径上的所有节点都直接连接到根节点上,以使得合并后的树的链长度最短。
class UnionFind{
public:
    // parent[i] = k : i的父亲是k
    vector<int> parent;
    // rank[i] = k : 如果i是代表节点,rank[i]才有意义,否则无意义
	// i所在的集合大小是多少
    vector<int> rank; 
    // 一共有多少个集合
	int sets;
	UnionFind(int size) : parent(vector<int> (size)), rank(vector<int> (size, 1)), set(size){
	for (int i = 0; i < size; ++i){
		parent[i] = i;
	}
	int findparent(int x){
		return x == parent[x] ? x : (parent[x] = findparent(parent[x]));
	}
	void to_union(int a, int b){
	    int pa = findparent(a);
	    int pb = findparent(b);
	    if (pa != pb){
	        if (rank[pa] >= rank[pb]){//注意使用父节点的rank进行比较
	            parent[pb] = pa; 
	            rank[pa] += rank[pb];
	        }
	        else{
	            parent[pa] = pb;
	            rank[pb] += rank[pa];
	        }
	        set--;
	    }
	}
	bool isSameSet(int a, int b){
	    return findparent(a) == findparent(b);
	}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值