并查集总结

定义:

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。主要应用在一些有N个元素的集合应用问题中,如开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。

并查集的基本概念

  • 集合:在并查集中,一个集合是由一组元素组成的,这些元素之间具有某种关系,使得它们可以被视为一个整体。每个集合都有一个唯一的代表元素,通常称为该集合的根节点或代表。
  • 树形结构:并查集使用树形结构来表示集合之间的关系。在树中,每个节点代表集合中的一个元素,而指针(或链接)则表示元素之间的父子关系。树的根节点代表整个集合的代表元素。

并查集的基本操作

  1. 初始化(Make_Set):在开始时,每个元素都被视为一个独立的集合。因此,初始化操作就是将每个元素作为一个单独的树,即每个元素的父节点都是它自己。
  2. 合并(Union_Set):合并操作是将两个集合合并成一个集合。为了实现这一操作,我们需要找到两个集合的代表元素(即根节点),然后将其中一个根节点的父节点设置为另一个根节点,表示将这两个集合合并成一个集合。这样,合并后的集合的代表元素就是新设置的根节点。
  3. 查找(Find):查找操作是查询一个元素属于哪个集合。为了找到元素所在的集合,我们需要从该元素开始,沿着父节点指针不断向上查找,直到找到根节点为止。这个根节点就是该元素所在的集合的代表元素。

路径压缩技术

为了提高查找效率,我们可以使用路径压缩技术。在每次查找操作中,我们将查找路径上的每个节点的父节点直接设置为根节点。这样,下次查找时就可以直接从节点跳到根节点,无需再遍历整个路径。这种技术可以大大降低树的高度,从而提高查找效率。

并查集的应用

并查集在许多实际问题中有广泛的应用,例如:

  • 连通性问题:在图形理论中,可以使用并查集来判断图中的节点是否属于同一个连通分量。
  • 最小生成树问题:在构建最小生成树时,可以使用并查集来合并已连接的节点所属的集合,从而确保生成的树是连通的且边的权值和最小。
  • 社交网络分析:在社交网络中,可以使用并查集来分析用户之间的关系,例如判断两个用户是否属于同一个社交圈子。

总之,并查集是一种高效处理不相交集合问题的数据结构,通过树形结构和路径压缩技术,可以实现快速的集合合并和查询操作。总的来说,并查集是一种高效处理不相交集合问题的数据结构,其时间复杂度接近线性,空间复杂度为O(n)。在实际应用中,我们可以使用并查集来解决一些需要快速合并和查找集合的问题,如连通性问题、最小生成树问题等。

题目实现:(并查集)

输入格式

第一行包含两个整数 N,M ,表示共有 N 个元素和 M 个操作。

接下来 M 行,每行包含三个整数 Zi​,Xi​,Yi​ 。

当Zi​=1 时,将 Xi​ 与 、Yi​ 所在的集合合并。

当Zi​=2 时,输出Xi​ 与Yi​ 是否在同一集合内,是的输出 Y ;否则输出 N 。

输出格式

对于每一个 Zi​=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。

输入输出样例

输入 #1复制

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出 #1复制

N
Y
N
Y

说明/提示

对于 30% 的数据,N≤10,M≤20。

对于 70% 的数据,N≤100,M≤103。

对于 100% 的数据,1≤N≤104,1≤M≤2×105,1≤Xi​,Yi​≤N,Zi​∈{1,2}。

代码实现:

#include<stdio.h>  
#include<stdlib.h>  
#include<stdbool.h>  
  
#define MAXSIZE 10100  // 定义并查集的最大大小为10100  
  
// 定义两个全局数组,father数组存储每个节点的父节点,size数组存储每个集合的大小  
int father[10100], size[10100];  
  
// 初始化函数,为并查集的所有节点设置初始的父节点为自身  
void make(int size) {  
 for (int i = 1; i <= size; i++)  
 father[i] = i; // 以自己为代表  
}  
  
// 查找函数,使用路径压缩技术,查找节点i的根节点  
int find(int i) {  
 if (i != father[i]) // 如果当前节点不是根节点  
 father[i] = find(father[i]); // 则递归地查找它的父节点的根节点,并进行路径压缩  
 return father[i]; // 返回根节点  
}  
  
// 判断两个节点是否属于同一个集合  
bool Set(int x, int y)  
{  
 return find(x) == find(y); // 如果它们的根节点相同,则它们属于同一个集合  
}  
  
// 合并两个集合,即将集合x的根节点设置为集合y的根节点  
void un(int x, int y) {  
 father[find(x)] = find(y);  
}  
  
int main()  
{  
 int n, m, z, x, y;  
 scanf("%d%d", &n, &m); // 读取节点的数量和操作的数量  
 make(n); // 初始化并查集  
  
 while (m--) { // 对每个操作进行处理  
 scanf("%d%d%d", &z, &x, &y); // 读取操作类型和两个节点的编号  
 if (z == 1) { // 如果操作类型为1,表示要合并两个集合  
 if (!Set(x, y))  // 如果x和y不在同一个集合中  
 un(x, y); // 则合并这两个集合  
 }  
 else { // 如果操作类型为2,表示要查询两个节点是否属于同一个集合  
 if (Set(x, y)) // 如果x和y在同一个集合中  
 printf("Y\n"); // 则输出"Y"  
 else   
 printf("N\n"); // 否则输出"N"  
 }  
 }  
 return 0;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值