数据结构之并查集

一、并查集的原理

在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合,开始时,每个元素自成一个单元素集合,然后按一定规律将同一组的元素集合合并。在此过程中要反复用到查询某个元素归属于哪个集合的运算,适合于描述这类问题的抽象数据结构类型称为并查集(union-find-set)

比如作者有大学同学,高中同学,初中同学,他们彼此不认识。就会分为三个集合。

按10人来算,将其按编号分为0-9,

分为不同的团体

用数组来表示该树形关系,数组中的非负数代表其父节点,负数表示该结点为根结点,且该树形有abs(负数)个结点。

之后,机缘巧合下,大学同学和初中同学在一场聚会中认识了,就将其合并为一个集合。

通过以上例子可知并查集一般可解决以下问题:

1.查找元素属于哪一个集合
2.查看两个元素是否属于同一个集合
3.将两个集合归并为一个集合
4.得到集合的个数

二、并查集的实现

1.这里我使用map存储名字和其对应vector的下标,vector来存储其关系。
cpp 复制代码
class UnionFindSet{
public:
	UnionFindSet(int n) {
		v.reserve(n);
	}
private:
	vector<int> v;
	map<T,int> m;
};
2.push实现去添加新元素
cpp 复制代码
void push(T&& name) {
	v.push_back(-1);
	m[name] = v.size() - 1;
}
void push(const T& name) {
	v.push_back(-1);
	m[name] = v.size()-1;
}

这里实现右值引用和const左值引用两个版本

3.给一个元素,找见其元素所在集合的位置
cpp 复制代码
	//给一个元素,找见其元素所在集合的位置
	int UnionFind(const T& name) {
		if (m.count(name) == 0) {
			return -1;
		}
		else {
			//通过循环遍历,找见v[index]为负数的位置
			//该index就为根节点的位置
			int index= m.find(name)->second;
			while (v[index] >= 0) {
				index = v[index];
			}
			return index;
		}
	}
4.查找集合的个数
cpp 复制代码
	//集合的个数
	size_t Count()const {
		size_t count = 0;
		for (int i = 0; i < v.size(); i++) {
			if (v[i] < 0) {
				count++;
			}
		}
		return count;
	}
5.查找两个元素是否为同一个集合,并合并
cpp 复制代码
	//合并两个元素为同一个集合
	bool merge(const T& name1, const T& name2) {
		//查找两个元素是不是同一个集合
		int x1 = UnionFind(name1);
		int x2 = UnionFind(name2);
		if (x1 == x2) {//因为有相同的根节点,所以为同一个集合
			return false;
		}
		else {
			v[x1] += v[x2];//将v[x2]存储的内容加在v[v1]上更新新集合的结点数量
			v[x2] = x1;//将v[x2]指向父节点
			return true;
		}
	}
//也可合并多个元素,利用可变参数包
	template<class...Args>
	void merge(const T& name1, const T& name2, Args&&... args) {
		merge(name1, name2);
		if constexpr (sizeof...(args) > 0) {//constexpr可以在编译时检查,防止传参出现问题
			merge(name2, forward<Args>(args)...);//这里用完美转发去保持其右值属性不变。
		}
	}

三、并差集的应用

1.省份数量https://leetcode.cn/problems/number-of-provinces/description/
cpp 复制代码
class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        vector<int> v;
        v.resize(isConnected.size(),-1);
        auto find=[&v](int index){//寻找根节点的数组下标
            while(v[index]>=0){
                index=v[index];
            }
            return index;
        };
        auto merge=[&v,&find](int a,int b){//合并两个集合
            int a1=find(a);
            int b1=find(b);
            if(a1!=b1){
                v[a1]+=v[b1];
                v[b1]=a1;
            }
        };
        for(int i=0;i<isConnected.size();i++){
            for(int j=0;j<isConnected.size();j++){
                if(isConnected[i][j]==1){//建立集合的关系
                    merge(i,j);
                }
            }
        }
        int count=0;
        for(int i=0;i<v.size();i++){
            
            if(v[i]<0){//判断"省份"的数量
                count++;
            }
        }
        return count;
    }
};
2.等式方程的可满足性https://leetcode.cn/problems/satisfiability-of-equality-equations/description/
cpp 复制代码
class Solution {
public:
    bool equationsPossible(vector<string>& equations) {
        vector<int> v;
        v.resize(26,-1);
        auto find=[&v](int index){
            while(v[index]>=0){
                index=v[index];
            }
            return index;
        };
        auto merge=[&v,&find](int x,int y){
            int x1=find(x);
            int y1=find(y);
            if(x1!=y1){
                v[x1]+=v[y1];
                v[y1]=x1;
            }

        };
        for(auto& e:equations){
            if(e[1]=='='){//先将等于关系建立起来
                merge(e[0]-'a',e[3]-'a');
            }
            
        }
         for(auto& e:equations){
        if(e[1]=='!'){//判断两个不等的元素是否有相等关系
                int x=find(e[0]-'a');
                int y=find(e[3]-'a');
                if(x==y){//有就返回失败
                    return false;
                }
            }
         }
        return true;//遍历结束返回成功
    }
};
相关推荐
写写闲篇儿9 小时前
下一个更大元素(一)
数据结构·算法
炽烈小老头12 小时前
【每天学习一点算法 2025/12/19】二叉树的层序遍历
数据结构·学习·算法
Queenie_Charlie12 小时前
HASH表
数据结构·c++·哈希算法
im_AMBER14 小时前
数据结构 13 图 | 哈希表 | 树
数据结构·笔记·学习·算法·散列表
LYFlied14 小时前
【算法解题模板】动态规划:从暴力递归到优雅状态转移的进阶之路
数据结构·算法·leetcode·面试·动态规划
合方圆~小文15 小时前
4G定焦球机摄像头综合介绍产品指南
数据结构·数据库·人工智能
FMRbpm16 小时前
串练习--------535.TinyURL的加密和解密
数据结构·c++·新手入门
Bruce_kaizy17 小时前
c++单调数据结构————单调栈,单调队列
开发语言·数据结构·c++
阿坤带你走近大数据17 小时前
Python基础知识-数据结构篇
开发语言·数据结构·python