文章目录
自我介绍:hello!这里是欧_aita的频道,一个初学数据结构与算法的小白。
小欧的今日语录: 但行前路,不负韶华!
小欧的祝福语:让我们在未来的道路上共同进步!
大家可以在评论区畅所欲言,可以指出我的错误,在交流中共同进步。
如果你也恰好在学习C++或者数据结构与算法那就来看看主页吧—— 欧_aita。
一.并查集的定义⭐
1.1 主要操作
并查集(Disjoint Set)是一种数据结构,用于处理一些不交集的元素分组和查询问题。它主要支持两种操作:
合并(Union): 将两个集合合并为一个集合。
查找(Find): 确定一个元素属于哪个集合,通常通过找到集合的代表元素(也称为根节点)来实现。
并查集通常由一个数组构成,每个元素指向另一个元素,表示其父节点或者所属集合的代表元素。这种数据结构通常用于解决一些元素分组的问题,如连通性问题,网络连接状态的判断等。
1.2具体应用
这种数据结构常用于解决图论中的连通性问题,例如判断图中两个节点是否连通,或者在生成树算法中的边的选择等。
1.3 时间复杂度
1.将两个集合合并 近乎O(1)
2.询问两个元素是否在一个集合当中 近乎O(1)
使用近乎o(1)的说法是因为在路径压缩的这个过成程时间复杂度并不是O(1),但是这个过程之后就是O(1)。
二.并查集的理论⭐
2.1 简述并查集思想
树只不过是抽象出来的一种映射关系,实际运用的是数组和下标来实现的。数组会定义很大,而p[i]表示的是i这个元素的父节点。
具体过程如下:
数组中存储的元素是父节点的下标
此时路径压缩已完成,每个元素的父节点都是树的根节点。
以上是find()的大致过程。
接下来是合并集合,将两个数组合并
可以看见令另一个集合的根节点的父节点设为另一个集合的根节点就是合并。
2.2 操作内容
关键操作包括:
初始化: 每个元素独立成为一个集合,通常将每个元素的父节点指向自己。
合并操作(Union): 将两个元素所在的集合合并为一个集合,通常通过将其中一个元素的根节点指向另一个元素的根节点来实现。
查找操作(Find): 确定元素所属的集合,通常通过不断向上查找父节点,直到找到根节点(代表元素)。
为了提高效率,常常会使用路径压缩和按秩合并等优化策略。路径压缩是在查找操作中,将查找路径上的所有节点直接连接到根节点,以减少树的深度,提高查询效率。按秩合并是根据树的高度来决定合并的顺序,将高度较低的树合并到高度较高的树上,以保持树的平衡,进而减少树的深度。
三. 具体代码实现⭐
3.1 声明
定义的这些可以先不看,然后在后续的代码片段里理解这些变量的作用。
#include <iostream>
using namespace std;
const int N = 100010;
int p[N],m,n;
3.2 查询两个元素是否都在同一个集合之中
这里主要提到以下两点 :
1.判断是否是树的根节点(if(p[x]==x))
2.求x的集合编号:(while (p[x]!=x)x=p[x];)
int find(int x)
{
if(find[x]!=x)x=p[x];
return p[x];
}
3.3 主函数加上合并集合
这里主要提到以下两点:
3.合并两个集合:px是x的集合编号,py是y的集合编号。p[x]=y;
4.路径压缩优化可以使并查集近乎O(1)的时间复杂度。
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i <= n; i++)p[i] = i;
while (m--)
{
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);//使用字符串会忽略空格之类的符号
if (op[0] == 'M')p[find(a)] = find(b);
else
{
if (find(a) == find(b))puts("yes");
else puts("NO");
}
}
return 0;
}
1.合并两个集合只用了一行代码if (op[0] == ‘M’)p[find(a)] = find(b);
2.op[]表示的是需要什么操作,如果op[0]=='M’就会进行合并操作,而之所以op[]数组需要定义多个数组元素空间是因为字符串最后一个元素是\0。
n代表的是元素个数,而m表示输入元素进入集合是需要多少步操作。
这篇文章就到此为止,如果觉得读完后对你有所帮助的话就点个赞吧,你们的支持是我最大的动力!