数据结构——并查集的详细解析和实现(代码片段)

努力学习的少年 努力学习的少年     2022-10-24     604

关键词:

  • 💂 个人主页:努力学习的少年
  • 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
  • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦

一.并查集的定义

1. 并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。
2. 并查集通常包含两种操作

  • 查找(Find):查询两个元素是否在同一个集合中
  • 合并(Union):把两个不相交的集合合并为一个集合

二.并查集的实现        

  • 如果有n个元素可能要合并,那么我们需要定义一个n个大小的元素的数组.
  • 数组的下标表示的是元素的编号,例如数组下标为1,则代表元素1.
  • 所有元素都初始化为-1,代表每个元素都是各自的集合,因此起初有n个集合

当有些集合 合并之后,数组会出现如下这种情况:

  • 如果元素的值是负数,则代表该元素是某个集合的根节点负数的绝对值是该集合的个数,且一个集合只有一个根节点.

如:元素1的值是-4,则说明元素1是某个集合的根节点,且该集合的元素个数是4.

  • 如果元素的值是正数,它仅仅是某个集合中的普通节点,且元素的值是它的父亲元节点的编号。

如:元 素2的值是1,则说明它的父亲节点的编号是元素1.

 并查集的查找(Find)

 并查集的查找判断两个元素是否在同一个集合上

例:怎样判断元素2和元素6元素是否在同一个集合上?

判断元素2和元素6的是否在同一个集合上,我们只需要判断元素2对应的集合的根节点与元素5对应集合的根节点是否相同,因为一个集合只有一个根节点,可见元素2对应的集合的根节点是元素1

元素6的根节点的对应的集合的根节点是元素4,因此它们不在同一个集合上。

判断两个元素是否在同一个集合只需要找到他们相对应的根节点,那么如何找到一个元素对应集合的根节点?

在一个集合当中,只有根节点它的值是负数,其余的元素都是正数,因此,给我们一个元素,我们需要判断对应的值是否为负数,如果不是,在通过元素的值,找到它的父亲节点的元素,再判断父亲节点是否负数,如此循环,直到找到一个元素,它的值为负数,则为该集合的根节点。

以元素6查找集合的根节点为例:

  • 元素6它存放的值是5,不是一个负数,说明元素6不是根节点,跳转到元素5.
  • 元素5存放的4,不是一个负数,说明元素5不是根节点,跳转到元素4.
  • 元素4存放的是-3,是一个负数,说明元素4就是元素6所对应集合的根节点。

Find的实现:

		bool Find(const int x, const int y) 
		int root_x = x, root_y = y;
		while (v[root_x] >= 0) 
			root_x = v[root_x];
		

		while (v[root_y] >= 0) 
			root_y = v[root_y];
		

		return root_x == root_y;
	

并查集的合并

并查集的合并是将一个集合合并到另一个集合上,并为一个更大的集合。

如果有两个元素,它们之间有交集,此时我们想要将这两个元素的对应的集合合并为一个集合,那么该如何合并呢?

如下:元素8和元素6它们之间存在交集,此时我们想要将8元素对应的集合与6元素对应的集合合并成一个集合,如何合并?

合并操作:

  • 先找到8元素对应集合的根节点,也就是元素1,再去找元素6对应集合的根节点,也就是元素4。
  • 集合1的个数加上集合2的个数,生成一个更大的集合,也就是元素1的内容加上元素4的内容。
  • 集合2的根节点值存放集合1对应的编号,表示的是集合2合并到集合1上。也就是将元素4的内容存放的元素1的编号。

 

代码实现:

	bool Union(const int x, const int y) 
		int root_x = x, root_y = y;
		while (v[root_x] >= 0) 
			root_x = v[root_x];
		
		//此时root_x为负数,则为x相对应集合的根节点
		while (v[root_y] >= 0) 
			root_y = v[root_y];
		
		//此时root_y为负数,则为y相对应集合的根节点
		if (root_x == root_y) 
			//两个元素是在同一个集合上
			//合并失败
			return false;
		

		v[root_x] += v[root_y];
		v[root_y] = root_x;
		return true;
	

并查集整体代码

class unionfind1 
public:
	unionfind1(int* x, size_t n) 
		for (int i = 0; i < n; i++) 
			v.push_back(-1);
		
	

	bool Find(const int x, const int y) 
		int root_x = x, root_y = y;
		while (v[root_x] >= 0) 
			root_x = v[root_x];
		

		while (v[root_y] >= 0) 
			root_y = v[root_y];
		

		return root_x == root_y;
	

	bool Union(const int x, const int y) 
		int root_x = x, root_y = y;
		while (v[root_x] >= 0) 
			root_x = v[root_x];
		
		//此时root_x为负数,则为x相对应集合的根节点
		while (v[root_y] >= 0) 
			root_y = v[root_y];
		
		//此时root_y为负数,则为y相对应集合的根节点
		if (root_x == root_y) 
			//两个元素是在同一个集合上
			//合并失败
			return false;
		

		v[root_x] += v[root_y];
		v[root_y] = root_x;
		return true;
	

private:
	vector<int> v;
;

如果并查集中的元素不是一个正数,可能是一个字符串,那么上面的并查集是不能帮我们实现的。

所以我们需要加一层哈希表将 字符串 数组 下标映射在一起,当判断两个元素是否在同一个集合中或者合并两个元素相对应的集合,需要先通过哈希表将 字符串 转换为 数组 下标。

 

template<class T>
class unionfind 
public:
	unionfind(T* x,size_t n) 
		for (int i = 0; i < n; i++) 
			v.push_back(-1);
            //将T类型与数组下标映射在一起
			mp.insert(pair<T,size_t>(x[i], i));
		
	

	bool Find(const T x, const T y) 
        //通过x,y找到相对应的数组下标
		size_t index_x = mp[x];
		size_t index_y = mp[y];
		while (v[index_x] >= 0) 
			index_x = v[index_x];
		

		while (v[index_y] >= 0) 
			index_y = v[index_y];
		

		return index_x == index_y;
	

	bool Union(const T x, const T y) 
        //通过x,y找到相对应的数组下标
		size_t index_x = mp[x];
		size_t index_y = mp[y];

		while (v[index_x] >= 0) 
			index_x = v[index_x];
		

		while (v[index_y] >= 0) 
			index_y = v[index_y];
		

		if (index_x == index_y) 
			//两个元素是在同一个集合上
			//合并失败
			return false;
		

		v[index_x] += v[index_y];
		v[index_y] = index_x;
		return true;
	

private:
	vector<int> v;
	unordered_map<T, int> mp;
;

相关题目

                        剑指 Offer II 116. 省份数量
                       684. 冗余连接
                      947. 移除最多的同行或同列石头

并查集的学习和模拟实现(代码片段)

并查集将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这... 查看详情

数据结构--并查集的原理及实现(代码片段)

...中了?因此就需要Find操作。并查集是一种不相交集合的数据结构,设有一个动态集合S=s1,s2,s3,.....sn,每个集合通过一个代表来标识,代表就是动态集合S中的某个元素。比如,若某个元素x是否在集合s1中(Find操作),返回集合s... 查看详情

并查集的原理及实现(代码片段)

一、定义  并查集是一种树型的数据结构,用于处理一些不相交集合(DisjointSets)的合并及查询问题。二、代码实现  在并查集结构中,用一个pre[]数组来存储当前结点的父亲结点,有两个函数,found()函数用来寻找根结点,... 查看详情

[文文殿下]并查集详细解读(代码片段)

初探并查集并查集(Disjoint-Set)是一种优美的数据结构,它擅长动态维护若干交集为空的集合,并且支持快速合并两个集合以及查找某个元素所在的集合。然而这只是并查集所能做的一点微小的工作,文文对并查集的理解是“一种... 查看详情

数据结构一篇文章学懂并查集+lrucache,拿来吧你!(代码片段)

...好文建议收藏!!并查集的概念并查集作为一种数据结构在处理需要将n个元素划分成不相交的集合,在逐步 查看详情

关于并查集的一切全在这里了(代码片段)

文章目录并查集初识「并查集」常用术语「并查集」基本思想「并查集」的两个实现方式QuickFind方式实现并查集QuickFind工作原理:代码实现与验证时间复杂度QuickUnion方式实现并查集QuickUnion的工作原理为什么QuickUnion比QuickFind... 查看详情

树的应用——并查集及实现代码(代码片段)

...—合并并查集的用途什么是并查集 并查集是一种树型的数据结构,用于处理一些不相交集合(disjointsets)的合并及查询问题。常常在使用中以森林来表示。 并查集支持以下3种操作:初始化(Initial)... 查看详情

树--12---并查集(代码片段)

文章目录并查集并查集是一种树型的数据结构并查集结构1.并查集的实现API设计UF(intN)构造方法实现union(intp,intq)合并方法实现代码:测试:案例1:计算机网诺连接2.UF_Tree算法优化eleAndGourp数组API设计find(intp)查询方法实现unio... 查看详情

❤️数据结构入门❤️(2-5)-并查集

文章目录一、并查集的定义二、并查集的图解三、并查集的实现1、并查集的插入2、并查集的删除3、并查集的修改4、并查集的查找四、并查集的刷题实战一、并查集的定义二、并查集的图解三、并查集的实现1、并查集的插入2、... 查看详情

数据结构----并查集(代码片段)

并查集并查集概念并查集的模拟实现模拟实现并查集优化Union优化压缩路径循环递归并查集例题并查集概念并查集在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集... 查看详情

并查集的学习和模拟实现(代码片段)

并查集将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这... 查看详情

并查集的学习和模拟实现(代码片段)

并查集将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这... 查看详情

并查集的实现(代码片段)

1intpar[MAX_N];//每个节点的父节点2intrank[MAX_N];//树的高度3//初始化n个元素4voidinit(intn)5for(inti=0;i<n;i++)6par[i]=i;//初始时每个节点自成一树7rank[i]=0;891011//查询树的根12intfind(intx)13if(par[x]=x)14returnx;1516else17r 查看详情

数据结构----并查集(代码片段)

并查集并查集概念并查集的模拟实现模拟实现并查集优化Union优化压缩路径循环递归(深度过深有栈溢出的风险)并查集例题并查集概念并查集在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每... 查看详情

并查集的基本操作和用法(代码片段)

并查集并查集的作用:1.合并区间2.判断两个数是否再同一个集合之中3.寻找联通子图的的个数并查集的关键函数find(x)与p[]数组寻找x的祖宗节点/* find函数用于寻找祖宗节点*/intfind(intx)if(p[x]!=x) find(p[x])returnp[x];/* p[N] 存储每... 查看详情

并查集的基本操作和用法(代码片段)

并查集并查集的作用:1.合并区间2.判断两个数是否再同一个集合之中3.寻找联通子图的的个数并查集的关键函数find(x)与p[]数组寻找x的祖宗节点/* find函数用于寻找祖宗节点*/intfind(intx)if(p[x]!=x) find(p[x])returnp[x];/* p[N] 存储每... 查看详情

并查集(入门)(代码片段)

首先先看一道很简单的并查集的题目:https://vjudge.net/contest/297398#problem/A这道题就是让你判断两两城镇之间是否联通  如果不联通就要修建一条道路 就我的理解来说,如果单独使用并查集就是为了合并有相同根结点(或者理... 查看详情

并查集的小节(代码片段)

寒假就看了并查集的视频,可是一直没怎么用了,现在终于还是拾起,看了这方面的视频还是很好理解的;看了挑战程序竞赛这本后,感觉大佬的思路就是简单,高效,可以首先写几个函数,分部实现各个功能,按照思路:1,... 查看详情