并查集的查询与合并详解

article/2025/8/26 23:45:44

文章目录

一、并查集的概念

二、并查集的实现

2、1 并查集不同集合(树)的形成

2、2 find()函数找一个元素集合的编号(元素所属于树的祖宗)

2、3  合并两个不同集合(合并两棵不同的树)

2、4 查询两个元素是否在一个集合

2、5 并查集例题训练1

2、6 并查集例题训练2

三、总结


标题:并查集的查询与合并详解

作者:@Ggggggtm

寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景

一、并查集的概念

  并查集是一种树形的数据结构。使用树型结构来存储数据。树根的编号即为整个树的标号,且每个节点存储的数据是他的父节点下标

  并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

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

二、并查集的实现

2、1 并查集不同集合(树)的形成

   我们把并查集不同集合(树)的实现主要分为以下几个点:

  1. 我们先给出n个数据,把n个数据存储到不同的集合当中(p[ i ] = i),在这里我们把每个p[ i ]分别看成一个不同集合(也就是一棵树)。
  2. p[ i ] = i,i即为这棵树的编号,这颗树下面的孩子节点存储的数据是父节点的下标。
  3. 当p[ i]=i 时,就相当于找到了根节点。
  4. 我们刚开始每个集合中的元素只有一个。后续合并后,集合元素个数不断增加。

2、2 find()函数找一个元素集合的编号(元素所属于树的祖宗)

  我们查找一个元素的集合,把元素的当作下标传给find()函数,代码如下:

int find(int x)
{if(p[x]!=x){p[x]=find(p[x]);}return p[x];
}

  我们p[x]中存储的正是他的父节点,从而就可以一直往上查找,直到p[ x ]=x时结束。当p[ x ]=x时,就相当于找到了根节点。此时的p[ x ]存储的是这棵树的编号。我这发现,刚开始每个集合当中都只有一个元素,也就是p[ x ],后面我们会对不同的集合进行合并,使得一个集合有多个元素。

  我们再找祖宗节点时进行了路径压缩。什么是路径压缩呢?路径压缩就是我们在查找某个元素的祖宗时,在找父节点的这条路经上的元素都指向祖宗节点,以便于我们后面的查找的时间复杂度近乎O(1)。

2、3  合并两个不同集合(合并两棵不同的树)

  我们直到了每棵树的根节点存储的是这个树的编号,而不是父节点。当我们要合并两颗树时,我们只需要把一棵树的根节点存储的编号改为另一棵树的根节点编号。简单的理解就是一个树的根节不再是根节点,而是一个子节点,该树的根节点存储的也不再是编号,而是存储的父节点,该父节点就是另一棵树的根节点。我们看代码:

//合并  把a的祖宗节点的父节点当作b的祖宗结点
p[find(a)]=find(b);

2、4 查询两个元素是否在一个集合

  我们有了find()函数,就可以很简单的判断出两个元素的是否在同一个集合当中(两个元素是否在同一个树中)。我们只需要判断两个元素集合的编号是否相同(两个元素的祖宗节点是否相同)即可。我们看代码:

//看a、b两个元素是否在同一个集合当中
if(find(a)==find(b))cout<<"Yes"<<endl;
elsecout<<"No"<<endl;

2、5 并查集例题训练1

 一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。

现在要进行 m 个操作,操作共有两种:

  1. M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  2. Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;

输入格式:

第一行输入整数 n和 m。

接下来 m行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式:

对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No

每个结果占一行。

数据范围:

1≤n,m≤10e5     1≤n,m≤10e5

输入样例:

4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4

输出样例:

Yes
No
Yes

  答案如下:

#include<iostream>
using namespace std;const int N=100010;
int p[N];//找祖宗+路径压缩
int find(int x)
{if(p[x]!=x){p[x]=find(p[x]);}return p[x];
}
int main()
{int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)p[i]=i;while(m--){char op[2];int a,b;cin>>op>>a>>b;if(op[0]=='M'){//合并  把a的祖宗节点的父节点当作b的祖宗结点p[find(a)]=find(b);}else{if(find(a)==find(b))cout<<"Yes"<<endl;elsecout<<"No"<<endl;}}return 0;
}

2、6 并查集例题训练2

给定一个包含 nn 个点(编号为 1∼n1∼n)的无向图,初始时图中没有边。

现在要进行 mm 个操作,操作共有三种:

  1. C a b,在点 aa 和点 bb 之间连一条边,aa 和 bb 可能相等;
  2. Q1 a b,询问点 aa 和点 bb 是否在同一个连通块中,aa 和 bb 可能相等;
  3. Q2 a,询问点 aa 所在连通块中点的数量;

输入格式

第一行输入整数 nn 和 mm。

接下来 mm 行,每行包含一个操作指令,指令为 C a bQ1 a b 或 Q2 a 中的一种。

输出格式

对于每个询问指令 Q1 a b,如果 aa 和 bb 在同一个连通块中,则输出 Yes,否则输出 No

对于每个询问指令 Q2 a,输出一个整数表示点 aa 所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤1051≤n,m≤105

输入样例:

5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5

输出样例:

Yes
2
3

  我们这个题相对于上个题就是对出了一个统计一个集合元素的个数。整体思路大同小异,我们直接看代码解析:

#include<iostream>
using namespace std;const int N=100010;
int p[N],cnt[N];
int find(int x)
{if(p[x]!=x){p[x]=find(p[x]);}return p[x];
}
int main()
{int n,m;cin>>n>>m;for(int i=0;i<n;i++){p[i]=i;cnt[i]=1;}while(m--){char op[5];int a,b;scanf("%s",op);if(op[0]=='C'){scanf("%d%d",&a,&b);if(find(a)==find(b))continue;cnt[find(b)]+=cnt[find(a)];p[find(a)]=find(b);}else if(op[1]=='1'){scanf("%d%d",&a,&b);if(find(a)==find(b))printf("Yes\n");elseprintf("No\n");}else{scanf("%d",&a);printf("%d\n",cnt[find(a)]);}}return 0;
}

   注意,我们刚开始每个集合中的元素只有一个。后续合并后,集合元素个数不断增加。

三、总结

  我们主要掌握find()函数,并查集算法中,最为核心的就是find()函数。在这个算法中,路径压缩给我们的算法效率提高了很多,这个也是需要理解的。 合并、查询是并查集的两个主要操作,我们也应该熟悉理解。

  我们对并查集的讲解就到这里,希望以上内容对你有所帮助。

  感谢阅读ovo~ 


http://chatgpt.dhexx.cn/article/ITCf0Eop.shtml

相关文章

并查集实现及其应用

先看看度娘给出的定义吧&#xff1a; 并查集&#xff0c;在一些有N个元素的集合应用问题中&#xff0c;我们通常是在开始时让每个元素构成一个单元素的集合&#xff0c;然后按一定顺序将属于同一组的元素所在的集合合并&#xff0c;其间要反复查找一个元素在哪个集合中。这一类…

超级简单并查集详解

一、概述 并查集&#xff0c;在一些有N个元素的集合应用问题中&#xff0c;我们通常是在开始时让每个元素构成一个单元素的集合&#xff0c;然后按一定顺序将属于同一组的元素所在的集合合并&#xff0c;其间要反复查找一个元素在哪个集合中。 其实说白了大部分还是用于寻找两…

并查集(java)

介绍 &#xff1a; 并查集属于数据结构的一种 是高等数据结构最基础的一部分&#xff0c;主要分为普通并查集 种类并查集以及带权并查集。它是一种用于管理元素所属集合的数据结构&#xff0c;这里的集合我们可以理解为一颗数 每个元素都是树上的有一个分叉&#xff0c;顺着分叉…

C++并查集

文章目录 并查集的原理并查集的实现代码并查集的典型应用 并查集的原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用…

c++并查集(详细总结)

老话重谈&#xff0c;先看定义 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合&#xff08;disjoint sets&#xff09;的合并及查询问题。常常在使用中以森林来表示。 首先得明白一些概念&#xff1a; 什么是树&#xff0c;什么是森林&#xff08;由树组成的叫…

Java——并查集

概念 当我们将多个元素分配到不同的集合中&#xff0c;这些集合有的是相关的&#xff0c;有的是不相关的。并查集就是用来查找两个元素是否在同一个集合中的 其主要实现方式是&#xff1a;将所有的元素以下标的形式存储在数组中。例如一共有十个人&#xff0c;那么就将这些人…

并查集Python版

以下来自于leetcode 使用数据结构&#xff1a;并查集 思路&#xff1a;由于相等关系具有传递性&#xff0c;所有相等的变量属于同一个集合&#xff1b;只关心连通性&#xff0c;不关心距离&#xff0c;因此很容易想到并查集。&#xff08;很容易嘛&#xff0c;反正我想不到&am…

并查集详解

文章目录 并查集一、简介1.定义2. 并查集的实现与优化 二、练习1.合并集合2.连通块中点的数量3. 食物链 三、总结 并查集 一、简介 1.定义 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题&#xff08;即所谓的并、查&#xff09;。比如说&am…

带权并查集

带权并查集需要先理解一般的并查集&#xff0c;不明白的可自行先搜索有关内容 一般的并查集主要记录节点之间的链接关系&#xff0c;而没有其他的具体的信息&#xff0c;仅仅代表某个节点与其父节点之间存在联系&#xff0c;它多用来判断图的连通性&#xff0c;如下图所示&…

并查集,不就一并和一查?

什么是并查集 并查集这种数据结构&#xff0c;可能出现的频率不是那么高&#xff0c;但是还会经常性的见到&#xff0c;其理解学习起来非常容易&#xff0c;通过本文&#xff0c;一定能够轻轻松松搞定并查集&#xff01; 对于一种数据结构&#xff0c;肯定是有自己的应用场景和…

数据结构——并查集

并查集是一种数据结构&#xff0c;是树的一种应用&#xff0c;用于处理一些不交集&#xff08;一系列没有重复元素的集合&#xff09;的合并以及查询问题。并查集支持如下操作&#xff1a; 查询&#xff1a;查询某个元素属于哪个集合&#xff0c;通常是返回集合内的一个“代表…

并查集详解(C/C++)

并查集算法详解&#xff08;C&#xff09; 并查集基础并查集是什么&#xff1f;并查集的作用是什么&#xff1f;并查集的结构合并查询 代码实现优化1&#xff1a;避免退化&#xff08;按秩合并&#xff09;代码优化 优化2&#xff1a;路径压缩代码优化 最终代码实现复杂度分析经…

并查集及其应用

并查集的基本操作: 1.合并两个集合 2.查询两个元素的祖宗节点 扩展: 1.记录每个集合的大小 将集合大小绑定到代表元素节点上 就是并查集的思想 (不是每个元素都是正确的 但是代表元素是正确的) 2.记录每个点到根节点的距离 绑定到每个元素身上 因为每个元素到根节点的距离…

并查集(Union-Find) (图文详解)

文章目录 并查集基础知识定义C实现优化 精选算法题(Java实现)实现并查集交换字符串中的元素最长连续序列 - 字节面试常考连通网络的操作次数最大岛屿数量 (三种解法)省份数量冗余连接冗余连接Ⅱ情侣牵手(困难)移除最多的同行或同列石头等式方程的可满足性 结语 并查集基础知识 …

什么是 “并查集” ?

导语&#xff1a;并查集是一种精巧的算法&#xff0c;本身并不难理解&#xff0c;却很常用&#xff0c;在许多场景下都能找到并查集的身影。 本文作者封承成&#xff0c;年仅12岁&#xff0c;非常感谢他的投稿。 并查集是什么 并查集&#xff0c;是一种判断“远房亲戚”的算法。…

并查集(Disjoint Set)

目录 ❤️什么是并查集&#xff1f; &#x1f3b6;实现方法1 &#x1f414;实现方法2 &#x1f383;题目1 ❤️什么是并查集&#xff1f; 并查集是一种数据结构&#xff0c;用于处理一些不交集&#xff08;Disjoint sets&#xff0c;一系列没有重复元素的集合&#xff09;的…

并查集

参考 https://www.cnblogs.com/asdfknjhu/p/12515480.html https://www.bilibili.com/video/BV13t411v7Fs?p3 https://leetcode-cn.com/problems/number-of-provinces/solution/python-duo-tu-xiang-jie-bing-cha-ji-by-m-vjdr/ 一、基本概念 并查集是一种数据结构 并查集这…

并查集(详细解释+完整C语言代码)

目录 1概论 2.树的表现形式 3.代码实现 3.1创立集合 3.2合并 3.3查询 3.4路径压缩 第一个方法&#xff1a;查找时优化 第二个方法&#xff1a;合并时优化&#xff08;加权标记法&#xff09; 4.完整代码 4.1优化前 4.2优化后 1概论 并查集是一种十分精巧且实用的树形…

时间序列预测的一般步骤

一、ARIMA模型概述 ​​ ARMA模型就是AR和MA的简单结合&#xff0c;同时包含了历史数值项和错误项。由于AR和MA模型都对时间序列有平稳性要求&#xff0c;ARMA模型也存在这个限制&#xff0c;因此我们将其拓展到ARIMA模型&#xff0c;其可以解决非平稳性问题。引入的差分概念是…

时间序列预测算法总结

时间序列算法 time series data mining 主要包括decompose&#xff08;分析数据的各个成分&#xff0c;例如趋势&#xff0c;周期性&#xff09;&#xff0c;prediction&#xff08;预测未来的值&#xff09;&#xff0c;classification&#xff08;对有序数据序列的feature提…