并查集详解

算法笔记:并查集 专题:并查集 一、引入         在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪哪个集合中。         该问题看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往超过了空间的限制,计算机无法承受;而且复杂度较高,实现过程较复杂。因此,只能采用一种特殊数据结构— 阅读详情

引入

例题:(洛谷 P3367 【模板】并查集)

第一行包含两个整数 N , M N,M N,M ,表示共有 N N N 个元素和 M M M 个操作。
接下来 M M M 行,每行包含三个整数 Z i , X i , Y i Z_i,X_i,Y_i Zi​,Xi​,Yi​ 。
当 Z i = 1 Z_i=1 Zi​=1 时,将 X i X_i Xi​ 与 Y i Y_i Yi​ 所在的集合合并。
当 Z i = 2 Z_i=2 Zi​=2 时,输出 X i X_i Xi​ 与 Y i Y_i Yi​ 是否在同一集合内,是的输出 Y;否则输出 N。

显然可以暴力解决。。。

请添加图片描述
这就要用到一种数据结构——并查集了!

并查集

并查集可以看做是一种森林,初始时每个节点都指向它自己。

我们来打一个合适的比喻:现在有四位武林高手,它们各自创建了自己的门派,开始都只有他们自己一人:

请添加图片描述
现在1号大师和2号大师打了一架,2号大师输了,加入了1号大师的门派:

请添加图片描述
3号大师和4号大师打了一架,4号大师输了,加入了3号大师的门派:

请添加图片描述
这时,4号(已经不能称之为大师了)去找2号打了一架,徒弟惹了事自然要师傅担着了,所以3号大师率领整个门派加入了1号大师:

请添加图片描述
这就是并查集的建立过程,那如果我们想知道一位好汉是哪一门派的怎么办?当然是找他师傅,通过他师父找他师傅的师傅,再找他师傅的师傅的师傅。。。一直找到掌门人。

用代码怎么实现呢?

int root(int x)
{
	if(x==f[x])//如果他是掌门人
		return x;//他所在的门派就是他自己的
	return root(f[x]);//找师傅
}

那么帮派之间的合并又是怎样完成的呢?自然是找到两位好汉所在门派的掌门人,然后让一个掌门人加入另一个掌门人:

void join(int x,int y)
{
	int r1=root(x),r2=root(y);//找掌门人
	if(r1!=r2)//如果它们不是一个门派
		f[r1]=r2;//打不过就加入
}

并查集的优化——路径压缩

假设我们有这样一个门派:
请添加图片描述

那这样不行啊,下达命令太慢,友军还没等到救援就已经被灭了。。。

那应该怎么办呢?采用 中央集权统治 路径压缩!

路径压缩后的并查集变成了这样:

请添加图片描述
这么神奇的功能是怎么实现的呢?

int root(int x)
{
	if(x==f[x])
		return x;
	f[x]=root(f[x]);//路径压缩,直属中央管辖
	return f[x];
}

注意!路径压缩会破坏树形结构!在题目不需要维护树形结构时才可使用。

并查集的优化——按秩合并

假设有两个帮派为了对付共同的敌人,同仇敌忾,想要友好建交,将两个帮派合并,这时它们的合并不在乎谁是老大,只要合并就行。

那么,我们应该让哪个帮派并入哪个帮派更好呢?显然,将更小的帮派并入更大的帮派更好,这样省事省力。

事实上,在并查集中,一般并不需要维护两个节点的先后关系,而只关心两个节点的所在集合。使用按秩合并,可以减少查询的时间。

按秩合并分为两种:按点的数量合并和按树的高度合并。这里采用树的高度。

void join(int x,int y)
{
	int r1=root(x),r2=root(y);
	if(r1!=r2)
	{
		if(h[r1]<h[r2])
			f[r1]=r2;
		else
		{
			f[r2]=r1;
			if(h[r1]==h[r2])
				h[r1]++;//增加树高
		}
	}
}

注意,使用前将 h [ ] h[] h[]数组初始化为 1 1 1。

为什么两个树高度相同,合并时就要加 1 1 1呢?我们来看以下例子:

请添加图片描述
它们高度相同,假设我们将节点 4 4 4加到节点 1 1 1:

请添加图片描述
显然,树高加 1 1 1。

并查集的终极优化——路径压缩&按秩合并

我们要想达到真正飞一般的速度,我们要既使用路径压缩,又使用按秩合并!

代码:(其实就是放到一起)

int root(int x)
{
	if(x==f[x])
		return x;
	f[x]=root(f[x]);
	return f[x];
}
void join(int x,int y)
{
	int r1=root(x),r2=root(y);
	if(r1!=r2)
	{
		if(h[r1]<h[r2])
			f[r1]=r2;
		else
		{
			f[r2]=r1;
			if(h[r1]==h[r2])
				h[r1]++;
		}
	}
}

这个方法有多快呢?它的复杂度为 O ( α ( n ) ) O(\alpha(n)) O(α(n)),其中 α ( n ) \alpha(n) α(n)是阿克曼函数的反函数。

不清楚?这么说吧,百度百科对 α ( n ) \alpha(n) α(n)函数是这么说的:

因为Ackermann函数的增长很快,所以其反函数 α ( x ) α(x) α(x)的增长是非常慢的,对所有在实际问题中有意义的 x x x, α ( x ) ≤ 4 α(x)≤4 α(x)≤4,所以在算法时间复杂度分析等问题中,可以把 α ( x ) α(x) α(x)看成常数。

事实上,当
x ≤ 2 2 1 0 19279 x≤2^{2^{10^{19279}}} x≤221019279
时, α ( x ) ≤ 5 α(x)≤5 α(x)≤5。

完整代码

#include<iostream>
#include<cstdio>
#define MAXN 10010
using namespace std;
int n,m;
int f[MAXN];
int h[MAXN];
int root(int x)
{
	if(x==f[x])
		return x;
	f[x]=root(f[x]);
	return f[x];
}
void join(int x,int y)
{
	int r1=root(x),r2=root(y);
	if(r1!=r2)
	{
		if(h[r1]<h[r2])
			f[r1]=r2;
		else
		{
			f[r2]=r1;
			if(h[r1]==h[r2])
				h[r1]++;
		}
	}
}
int op,x,y;
void init()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		f[i]=i,h[i]=1;
}
int main()
{
	init();
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)
			join(x,y);
		else
			if(root(x)==root(y))
				printf("Y\n");
			else
				printf("N\n");
	}
	return 0;
}
并查集 文章目录一、并查集定义二、并查集思想三、并查集代码:(1)初始化(2)查找(3)合并四、路径压缩 一、并查集定义 1. 并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。 2. 并查集通常包含两种操作 查找(Find):查询两个元素是否在同一个集合中 合并(Union):把两个不相交的集合合并为一个集合 注意:双亲结点就是父结点 二、并查集思想 如图现在大陆上有下面六位鼎鼎大名的忍者,且各自为王!     & 阅读详情

相关推荐

并查集实例详解

一、简介并查集,是一种很有用的数据结构。可以把它想象为多棵独立的树。 并查集的常用基本操作有 查找任意两个树节点,看看它们是否属于同一棵树(其实就是查不同节点的根节点是否一样即可),如下图b & e 同属于根为c的树,所以它们在同一个集合;而h & g则不属于同一集合。 合并这些独立的树,成为一棵更庞大的树。(其实也很简单,就是将一颗树的根节点成为另一个树根节点之下的孩子即可) 合并操作如图所示:

LHJ884的专栏 2552

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

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

ReadyGo!!!的博客 2万+

UG NX与PLC-1500的在环虚拟测试

TIA、PLCSIM、NetToPLCsim、KEPServerEX以及UG NX的在环虚拟测试

lvtlvtlvtlvt的博客 4220

【高级数据结构】并查集

前面讲解了并查集的基本应用—一处理集合问题。在这些基本应用中,点之间只有简单的归属关系,而没有权值。如果在点之间加上权值,并查集的应用会更广泛。如果读者联想到树这种数据结构,会发现并查集实际上是在维护若干棵树。并查集的合并和查询优化,实际上是在改变树的形状,把原来“细长”的,操作低效的大量“小树”,变为“粗短”的、操作高效的少量“大树”。如果在原来的“小树”上,点之间有权值,那么经过并查集的优化变成“大树”后,这些权值的操作也变得高效了。定义一个权值数组dd[]d,把节点iii。

Antonio915的博客 1万+

ST MCSDK V6.2.0实战:手把手教你配置HSO-ST观测器,体验500ms收敛的电机无感控制

本文详细介绍了ST MCSDK V6.2.0中HSO-ST观测器的配置方法,实现500ms内电流收敛的无感电机控制。从环境搭建、核心参数解析到无感启动优化,提供实战技巧和性能调优策略,帮助开发者快速掌握高效电机控制技术。

weixin_28720767的博客 579

GoldenDB 兼容模式冲突场景解析:MySQL 连接模式 vs Oracle 语法兼容

GoldenDB 兼容模式冲突场景解析:MySQL 连接模式 vs Oracle 语法兼容

weixin_45207751的博客 2250

万字长文,并查集(Union Find)精讲及应用实例

并查集(Union Find):一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。不交集指的是一系列没有重复元素的集合。合并(Union):将两个集合合并成一个集合。查找(Find):确定某个元素属于哪个集合。通常是返回集合内的一个「代表元素」。简单来说,并查集就是用来处理集合的合并和集合的查询。并查集中的「集」指的就是我们初中所学的集合概念,在这里指的是不相交的集合,即一系列没有重复元素的集合。

白话机器学习 8502

能碳双控| AIRIOT智慧能碳管理解决方案

基于AIRIOT打造的智慧能碳管理平台解决方案结合大数据、物联网、人工智能(AI)、数字孪生等新一代信息技术,通过整合碳达峰、碳中和、实时碳价、碳配额和碳资产等多个模块,为组织提供了全方位、灵活且智能的碳资产管理解决方案,有助于实现碳管理目标、提升可持续性,并适应碳市场的不断变化。

AIRIOT的博客 1808

并查集之种类并查集——详解

知乎上看到的一篇文章,解释得非常到位了,有图有文字有题目 种类并查集详解

随意凯的博客 1059

YOLOv8改进策略【Neck】| CGA Fusion:内容引导的注意力融合模块,空间权重引导的多模态特征自适应融合

本文记录的是利用CGA Fusion 模块改进 YOLOv8 的多模态融合部分。(Content-Guided Attention Fusion)通过内容引导注意力生成空间权重,引导高低层特征的自适应融合。本文利用模块,通过内容引导注意力生成空间权重,自适应地融合两个模态的特征,在特征融合阶段实现跨模态语义对齐与噪声抑制,增强对不同模态互补特征的利用能力,从而提升模型在多模态场景下的检测鲁棒性与准确性。DEA-Net: Single image dehazing based on detail-enhanc

Limiiiing的博客 282

SAP-ABAP:SAP中的用户确认对话框:深入理解与实践POPUP_TO_CONFIRM

本文深入介绍了SAP中的用户确认对话框函数POPUP_TO_CONFIRM,包括其核心参数配置、返回值处理、应用场景和最佳实践。该函数是SAP二次开发中重要的交互工具,用于关键操作前获取用户确认,防止误操作。文章详细解析了参数设置技巧,强调必须全面处理所有可能的返回值,并提供了删除数据、批量操作等典型应用场景的代码示例。同时对比了其他类似弹出函数,帮助开发者选择合适工具。正确使用该函数可提升系统安全性、改善用户体验并符合SAP设计规范。

baidu_35680696的博客 970

c++ 并查集详解

获取代表元素:获取某个集合的代表元素(根节点)。在并查集中,每个集合都有一个代表元素,该代表元素是该集合中任意元素的祖先节点。通过遍历该元素的父指针,可以找到其所在的集合的代表元素(根节点)。首先找到需要合并的两个集合的代表元素(根节点),然后将其中一个集合的代表元素的父指针指向另一个集合的代表元素,从而实现合并。路径压缩:在查找过程中,将某个元素的父指针直接指向其所在集合的根节点,以减少后续查找的时间复杂度。通过遍历该元素的父指针,可以找到其所在的集合的代表元素(根节点),从而判断该元素是否属于该集合。

weixin_72389218的博客 2583

17、非线性动力学特征在情感语音与食管语音分析中的应用

本文探讨了非线性动力学特征在情感语音与食管语音分析中的应用。在情感语音识别中,选取Hurst指数、相关维数和Lempel-Ziv复杂度等混沌特征结合统计量,通过神经网络实现了中性、恐惧和愤怒情感的高效分类,全局成功率高达93.78%。在食管语音分析中,针对其缺乏明显周期性的问题,提出基于改进自相关方法的基频测量流程,包括包络计算、平滑与峰值细化,并对基频的物理意义提出思考。研究展示了两类语音在特征表现与技术方法上的差异,展望了其在客服、安全、医疗康复等领域的应用前景,并指出了未来在特征拓展、算法优化和发声机

sunny的博客 74

【并查集】 带权并查集详解

一.引入 并查集实际上是一颗由若干个树构成的森林,而如果还需要储存边的权值,则需要额外用一个数组d记录每个结点和其父节点的权值 这个思路其实很简单,但是因为路径压缩会改变点与点的连接关系,路径压缩后,点的父节点变为了根节点,所以需要更新d数组 二.查询函数写法 更新权值在查询操作的同时进行 int root_find(int x){ if(x==pre[x]) return x; int root=root_find(pre[x]); d[x]+=d[pre[...

Qiuker_jl的博客 2488

汇川AM系列ethercat控制伺服的使用说明(含转矩模式)

本文以一个实际例子,介绍ethercat伺服驱动器的工作原理,以及在汇川AM系列PLC中,如何点动、定位、速度、转矩控制ethercat伺服。

qq_34047402的博客 5111

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

带权并查集 详解

简介 带权并查集与普通并查集的区别在于,其每条边/每个点都有权值。因此,我们需要额外用一个数组来维护每个点 xxx 到其当前祖先 faxfa_xfax​ 的权值和,并在路径压缩的时候维护。 直接说可能较难理解,于是下面是一道例题。 P1169 Description 传送门 Solution 考虑对于每个点 xxx,维护其到其祖先 faxfa_xfax​ 的距离 depxdep_xdepx​,并对于每个并查集的根维护连通块大小 sizsizsiz。 对于一个 M 操作,令涉及到的战舰分别为 x,yx,yx,

Cherrt的博客 2705

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

详解并查集

一、概念并差集主要用来求解不相交集合的问题,主要针对于合并和查找两种算法。二、并差集实现并差集的实现主要包含了三个部分: 初始化并差集。 合并并差集。 查找并差集。 (1)并差集的初始化并差集的初始化是对单个数据建立了一个单独的集合,每个集合应该包含以下两个数据: 这个集合所表示的数据。 这个集合的根集合所在位置。 由以上两个数据,一般的并差集的结构一般有两种表示形式: 结构体构造。 数组构造。

ArchyLi 1101

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

并查集详解及应用

并查集详解及应用 什么是并查集 并查集是一种数据结构,由一个整型的数组和两个函数构成,本质是树,可以及解决很多图的问题。 整型数组:记录了每个点的前导点; 函数find():用于查找根节点; 函数join():合并; 自定义的并查集类代码如下 class JoinFind { int[] pre; //构造 public JoinFind(int n) { pre = new int[n]; for(int i=0; i<n; ++i) { pre[i] = i; } }

lastTianChen的博客 203
上一篇: AC自动机详解
下一篇: 染色问题(并查集)
Wu_while
博客等级 码龄6年 50粉丝 53原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值