数据结构(八):并查集详解 (多图+动图)

这篇具有很好参考价值的文章主要介绍了数据结构(八):并查集详解 (多图+动图)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、什么是并查集

二、并查集的存储结构

三、并查集的基本操作

(一)初始化

(二)Find操作

(三)Union操作

四、并查集的优化

(一)Union操作优化(小树并入大树)

(二)Find操作优化(压缩路径)


一、什么是并查集

        并查集的逻辑结构是一个包含N个元素的集合,如图:

并查集,数据结构,数据结构,c++

        我们将各个元素划分为若干个互不相交的子集,如图:

并查集,数据结构,数据结构,c++

        我们假设第一个集合中的元素为:苹果、橘子、香蕉等各种水果,结点10就表示水果1
        我们假设第二个集合中的元素为:油菜、香菜,芹菜等各种蔬菜,结点11就表示蔬菜。
     
  我们假设第三个集合中的元素为:高数、线代、计网等各种学科,结点9就表示学科。
       
我们假设第四个集合中的元素为:蓝莓、草莓、杨梅等各种水果,结点14就表示水果2。
       
(注:四个集合互不相交)

        

        下面有几个问题:

  1. 如何判断高数(结点6)是什么集合门类下的?
    从结点6向上找(6 -> 13 -> 9),结点9代表学科门类。
  2. 如何判断苹果(结点0)和橘子(结点12)是否属于同一集合?
    从结点0开始向上找(0 -> 1 -> 2 -> 3 -> 10)
    从结点12开始向上找(12 -> 10)
    所以,它两属于同一个集合
  3. 集合一中的水果要与集合四中的水果合成一组,这时应该怎么做?
    我们可以理解为结点10带领的是水果(1)大家族,结点14带领的是水果(2)大家族,只要结点10与结点14合并到一起,便可以实现两个集合的合并,其余结点不需要操作,如图:
    并查集,数据结构,数据结构,c++

        在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,只能用并查集来描述。

二、并查集的存储结构

        并查集的存储结构可以通过 树的双亲表示法 来理解。

        我们先来看一下树的双亲表示法:

        这种存储方式采用一组连续空间来存储每个结点,同时在每个结点中增设一个伪指针,指示其双亲结点在数组中的位置。如图所示,根结点下标为0,其伪指针域为-1。

并查集,数据结构,数据结构,c++

         该存储结构利用了每个结点(根结点除外)只有唯一双亲的性质,可以很快得到每个结点的双亲结点,但求结点的孩子时需要遍历整个结构。

        接下来,我们来看并查集:

        若设有一个全集合为 S ={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},初始化时每个元素自成一个单元素子集合,每个子集合的数组值为 -1,如图:

并查集,数据结构,数据结构,c++

         经过一段时间的计算,这些子集合合并为3个更大的子集合,并查集的树形表示和存储结构如图:

并查集,数据结构,数据结构,c++

         可见,并查集可用数组进行表示,数组下标序号表示该数据元素,数组值存放其双亲信息。

分析:

对于上一个图

结点 0 的数组值为 2 ,代表双亲是 2 ;

结点 2 的数组值为 7 ,代表双亲是 7 ;

结点 7 的数组值为 9 ,代表双亲是 9 ;
结点 9 的数组值为 14 ,代表双亲是 14 ;

结点 14 的数组值为 -1 ,代表该结点为根结点 ;

至此,我们仅通过数组这一数据结构便完成了结点信息的存放和结点双亲的查找。

   下面,我们用代码描述并查集:

  • 并查集的结构定义为:
    #define SIZE 100
    int UFSets[SIZE]; //集合元素数组

三、并查集的基本操作

(一)初始化

  • 并查集的初始化即使每个元素自成一个单元素子集合,每个子集合的数组值为-1
    void Initial(int S[])
    {
    	for (int i = 0; i < SIZE; i++)
    		S[i] = -1;
    }

(二)Find操作

  • 查找操作即在并查集S中查找并返回包含元素 x 的树的根
    int Find(int S[], int x)
    {
    	while (S[x] >= 0) //循环寻找 x 的根
    		x = S[x];
    	return x; //根的 S[] 小于0
    }

(三)Union操作

  • 合并操作即将两个子集合的根合并到一起
    void Union(int S[], int Root1, int Root2)
    {
    	//要求Root1与Root2是不同的,且表示子集合的名字
    	if (Root1 == Root2) return;
    	S[Root2] = Root1;
    }

    (Root2的双亲指向了Root1,意味着Root2带领的整个集合都指向了双亲Root1,实现了合并)

四、并查集的优化

(一)Union操作优化(小树并入大树)

  • 问题:若只有一个子集合,且这一个子集合是一条细长的链,若结点数是 n ,那么查找的最坏时间复杂度是O(n)
  • 优化思路:在每次Union操作构建树的时候,尽可能让树不长高
  • 方法
    1. 每个根结点不再用-1表示,用根结点的绝对值表示树的结点总数,例如,原先数组值如图

    并查集,数据结构,数据结构,c++

    图中表示结点 1 、13 、14是根结点。
    优化后为

    并查集,数据结构,数据结构,c++文章来源地址https://www.toymoban.com/news/detail-767804.html

    图中仍然表示结点 1、13、14为根结点,同时说明了根结点1子集合下共有4个元素,其他同理。
    2.Union操作,让小树合并到大树
    代码编写
    void Union(int S[], int Root1, int Root2)
    {
    	//要求Root1与Root2是不同的,且表示子集合的名字
    	if (Root1 == Root2) return;
    	if (S[Root2] > S[Root1]) //Root2结点数更少
    	{
    		S[Root1] += S[Root2];
    		S[Root2] = Root1; //小树合并到大树,即Root2指向Root1
    	}
    	else
    	{
    		S[Root2] += S[Root1];
    		S[Root1] = Root2;
    	}
    }
  •  结果:Union操作优化后,Find操作的最坏时间复杂度变为了

(二)Find操作优化(压缩路径)

  • 问题:反复查找某个结点的根结点,每次都会花费大量时间
  • 优化思路:只要查找一次,就将查找路径上的所有结点都挂到根结点下面,如图,查找L的根结点A,查找一次过后,就将E、B、L全部挂到根结点A之下
    并查集,数据结构,数据结构,c++
  •  方法
    代码编写
    int Find(int S[], int x)
    {
    	int root = x;
    	while (S[root] >= 0) root = S[root]; //循环找到根
    	while (x != root) //x不为根结点,则压缩路径
    	{
    		int t = S[x]; //t指向x的父节点
    		S[x] = root; //x直接挂到根结点下
    		x = t;
    	}
    	return root; //返回根节点编号
    }
  •  结果:Find操作优化后,Find操作的最坏时间复杂度为,是一个增长很缓慢的函数,通常<=4

到了这里,关于数据结构(八):并查集详解 (多图+动图)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】并查集

    并查集是简单的数据结构,学会并查集,为图打好基础。 是树状的数据结构,用于处理相交集合的合并与查询 通常用森林表示,一片森林表示一个集合 并查集一般需要完成 查找元素属于哪个集合 查看两个元素是否属于同一个集合 将两个集合归并成一个集合 集合的个数 假

    2024年02月19日
    浏览(35)
  • 【数据结构】--并查集

    目录 一、概念 ​编辑 二、应用场景--“连接”问题(属于同一Qu 三、实现思路  四、如何存储数据 五、定义接口 1.初始化(init) 2.其他 isSame() 六、抽象类 六、Quick Find【v1 所在集合的所有元素都指向 v2 的根节点】 1.Union 1.Union图解 2.注意点:  3.代码实现 2.find  1.find图

    2023年04月09日
    浏览(31)
  • 数据结构详细笔记——并查集

    集合:将各个元素划分为若干个互不相交的子集的集合 森林是m(m=0)棵互不相交的树的集合 优化思路:在每次Union操作构建树的时候,尽可能让树不长高 ①用根结点的绝对值表示树的结点的总数 ②Union操作,让小树合并到大树 优化思路:先找到根结点,再将查找路径上所有结

    2024年02月06日
    浏览(38)
  • 数据结构之并查集

    并查表原理是一种 树型的数据结构 ,用于处理一些不相交集合的合并及查询问题。并查集的思想是用一个数组表示了整片森林(parent),树的根节点唯一标识了一个集合,我们只要找到了某个元素的树根,就能确定它在哪个集合里。这类问题的抽象数据类型称为并查集(uni

    2024年02月12日
    浏览(36)
  • 【数据结构与算法】并查集

    并查集是一个树形结构,所谓的并查,就是 当我们有了一个节点,我们就能知道这个节点属于哪个集合 。 举个例子理解以下:战国时期有很多国家,它们会互相打仗,那么现在有两个互相不认识的人,如何知道对方是敌是友呢? 现在有一种方法:每个国家都有一个大王,我

    2023年04月15日
    浏览(36)
  • 算法与数据结构(九)--并查集

    1.处理对象:Disjoint Set,即“不相交集合”。 在一些应用问题中,需将n个不同的元素划分成一组不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定顺序将属于同一组元素的集合合并。其间要反复用到查询某个元素属于哪个集合的运算。适合于描述这类问题的

    2024年02月10日
    浏览(40)
  • 【数据结构】| 并查集及其优化实现

    以一个直观的问题来引入并查集的概念。 亲戚问题:有一群人,他们属于不同家族,同一个家族里的人互为亲戚,不同家族的人不是亲戚。随机指定两个人,问他们是否有亲戚关系。 以下图3个不相交的集合表示 3 个家族,当询问两个人是否有亲戚关系时,也就是问两个元素

    2024年02月09日
    浏览(37)
  • 计算机基础--->数据结构(9)【并查集】

    并查集是一种用于解决集合合并和查询问题的数据结构,主要用于实现有关集合的操作,它有两种主要操作,合并(union)和查找(find)。 查找(Find):用来确定元素属于哪个集合。它接受一个元素作为参数,并返回这个元素所属集合的代表元素。通过查找操作,可以判断

    2024年02月15日
    浏览(47)
  • Java高阶数据结构 & 并查集 & 最小生成树

    并查集与最小生成树 1.1 并查集的原理 在一些应用问题中,我们常常会遇到一类问题 一开始是一个人 后来新增的人可能与这个人有关系,也可能与这个人无关系。 一个人与一个人有关系,这个人与另一个人也有关系,那么三人都有关系。 有关系的和没关系的之间是不同的类

    2024年02月03日
    浏览(40)
  • 数据结构--并查集的进一步优化

    压缩路径 − − F i n d 操作,先找到根节点,再将查找路径上所有结点都挂到根结点下 color{red}压缩路径 -- Find操作,先找到根节点,再将查找路径上所有结点都挂到根结点下 压缩路径 − − F in d 操作,先找到根节点,再将查找路径上所有结点都挂到根结点下 每次Find操作,

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包