并查集【数据结构与算法】【C语言版-笔记】

news2024/10/2 22:17:50

目录

  • 一、需求分析
  • 二、并查集
  • 三、代码实现
    • 3.1 Find函数
    • 3.2 Union函数
    • 3.3 优化1
    • 3.4 终极优化2---压缩策略

一、需求分析

假设有n个互不相交的集合
◼问题1:给定某个集合中的一个元素,查找该元素属于哪个集合?
◼问题2:如何合并两个集合?

实例:
有n个村庄,有些村庄之间有连接的路,有些没有(有路连接的村庄视为同一个集合)
设计一个数据结构,能快速的执行下面两个操作
◼查询2个村庄之间是否有连接的路
◼连接两个的村庄

若使用数组、线性链表等其两者操作的复杂度至少是O(n),而并查集能够办到查询、连接的均摊时间复杂度都是O(log2n),非常适合解决这类“连接”相关的问题。

二、并查集

顾名思义,并查集是一种对集合以及集合里元素操作的结构,其中“并”就是合并,“查”就是查询某元素属于哪个集合,这也是它的两大核心操作

◼查找(Find):查找元素所在的集合(这里的集合指的是逻辑上(数学上)的集合而不是具体某个特定集合)
◼合并(Union):将两个元素所在的集合合并为一个集合

如何选择并查集的存储结构?从树的形状出发,我们知道一棵树上的叶子必定属于同一棵树(额,这好像是废话),把树看作集合,叶子作为集合的元素。给定一片叶子,找到它对应的树干(或根)就可以确定叶子的归属。数据结构中树的常用存储结构有三种方式:【双亲表示法,孩子表示法,孩子兄弟表示法】我们选择双亲表示法,因为这种设计方法很适合找到根结点,从而很容易确定元素所属集合。对于合并集合,我们只需要修改其中一个集合的parent指向另一个集合的 “根” 即可。

双亲表示法:
给定一块连续的内存空间存货结点,给每个结点附设一个指针器,指示它的双亲结点在存储空间中的位置
其存储表示如下:
#define MAX_TREE_SIZE 20
typedef int TElemType;
typedef struct {
	TElemType num;
	int parent;
} TNode;
typedef struct {
	TNode nodes[MAX_TREE_SIZE];
	int length;//结点数
} PTree

//并查集的存储表示(为了方便直接使用数组(集合为数集),且num既是集合中的元素也是结点本身在存储空间中的位置)
typedef TNode unionFind[MAX_TREE_SIZE];

(备注:为了方便直接使用数组(集合为数集),且num即是集合中的元素也是结点本身在存储空间中的位置

三、代码实现

规定:用一块连续的内存空间存储n个集合的全部元素,每个集合对应一棵树,树的根结点的parent值记为 -1

3.1 Find函数

//查找元素e所属的集合,即找到该集合的“根”元素,返回根元素
TElemType* Find(unionFind uf,TElemType e){
	int root=e;//当前元素本身
	int x=uf[e].parent;//e的双亲所在的位置
	while(x!=-1){
		root=x;
		x=uf[x].parent;
	}
	return root;
}

时间复杂度
最坏:O(n)、平均:O(log2n)、最好:O(1)

3.2 Union函数

//合并两个集合,rooti(i=1,2)为集合的根
void Union(unionFind uf,int root1,int root2){
	if(root1==root2) return;//如果是同一个集合,不用合并
	uf[root2].parent=root1;
}

时间复杂度O(1)

3.3 优化1

在进行Find的时,发现查找的长度和树的高度有关,且最坏时间复杂度是O(n),这时棵树变成了单支树(退化成为链表)。因此,可以从树高的角度出发减少树高从而达到优化Find的时间效率。优化思路是在每次Union的时候,尽可能的让树 “不长高”,让小的树合并到大的树(树的大小指的是结点数量的多少)或者是让矮的树合并到高树上。下面采用第一种,这种方法需要有一个计数器保存一个集合(树)的大小,我们直接利用一个集合的“根”的parent来保存集合的大小,同时为了保留根的标识(parent为-1),parent==集合大小的相反数

void Union(unionFind uf,root1,root2){
	if(uf[root1].parent<uf[root2].parent){
		uf[root1].parent+=uf[root2].parent;
		uf[root2].parent=root1;
	}else{
		uf[root2].parent+=uf[root1].parent;
		uf[root1].parent=root2;
	}n
	
}

优化后,Find最坏的时间复杂度变为:O(log2n)
(第二种方法—矮树合并到高树上,如何实现,大家可以自行思考)

3.4 终极优化2—压缩策略

所谓压缩是指压缩树的高度。我们对Find操作进行优化,当执行Find时,我们把传入的元素到根的路径上的结点(包含元素本身所在的结点)全部都直接挂在根的孩子位置上(如果已经是根的孩子了,则不用修改)。当再次查找该元素所属集合时,只需要常数级别的操作就可以完成查找。

void Find(unionFind uf,TElemType e){
	int root=e;//当前元素本身
	int x=uf[e].parent;//当前元素的双亲位置
	//找到元素所在集合的”根“
	while(x>=0){
		root=x;
		x=uf[e].parent;
	}
	while(e!=root){
		int t=uf[e].parent;//t表示路径上元素的位置,t等价uf[uf[e].parent].num,前面黄字部分已表明
		uf[e].parent=root;
		e=uf[t].num;
	}
	return root;
}

如下图,调用Find后
在这里插入图片描述
优化后时间复杂度
最坏: O ( α ( n ) ) O(\alpha(n)) O(α(n)),其中, α ( n ) \alpha(n) α(n)是比log2n增长速度小的数量级

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2185132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

建筑业挂靠行为的防范建议

在建筑行业中&#xff0c;挂靠行为的普遍存在给许多企业带来了法律风险和信誉风险。为了防范这些风险&#xff0c;企业需要采取一系列有效的措施。 一、加强资质管理 企业应当通过合法途径获取和提升自身的资质等级&#xff0c;避免因资质不足而产生挂靠的需求。加强资质管理是…

【半导体物理基础】第1章 半导体中的电子状态和能带,晶格结构,有效质量

目录 1.1 半导体晶格结构和结合性质 固体的种类 典型晶体 元素半导体 几种晶胞结构 晶向指数与晶面 半导体的晶体结构 金刚石结构 金刚石结构的结晶学原胞 硅、锗相关参数 硅、锗相关参数计算 闪锌矿结构 纤锌矿结构 氯化钠型结构 1.2 半导体中的电子状态和能带…

Study-Oracle-10-ORALCE19C-RAC集群搭建

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 ORACLE --RAC 搭建理念:准备工作要仔细,每个参数及配置都到仔细核对。环境准备完成后,剩下的就是图像化操作,没啥难度,所以图形化操作偷懒不续写了。 一、硬件信息及配套软件 1、硬件设置 RAC…

客厅落地台灯怎么摆放?五款客厅落地台灯款式分享

客厅落地台灯怎么摆放&#xff1f;客厅落地台灯是提升光线环境在室内光线质量的关键设备。但如果不慎购买到低质量的客厅落地台灯&#xff0c;可能会导致光线效果不佳&#xff0c;进而影响视力健康。因此&#xff0c;挑选一个可靠的品牌至关重要。那么&#xff0c;客厅落地台灯…

ubuntu 18.04 cuda 11.01 gpgpu-sim 裸机编译

1&#xff0c;环境 ubuntu 18.04 x86_64 cuda 11.01 gpgpu-sim master commit 90ec3399763d7c8512cfe7dc193473086c38ca38 2&#xff0c;预备环境 一个比较新的 ubuntu 18.04&#xff0c;为了迎合 cuda 11.01 的版本需求 安装如下软件&#xff1a; sudo apt-get instal…

Thinkphp/Laravel基于vue的的出版社书籍阅读管理系统

目录 技术栈和环境说明具体实现截图设计思路关键技术课题的重点和难点&#xff1a;框架介绍数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 技术栈和环境说明 采用PHP语言开发&#xff0c;开发环境为phpstudy 开发工具notepad并使用MYSQL数据库…

netty之NettyClient半包粘包处理、编码解码处理、收发数据方式

前言 Netty开发中&#xff0c;客户端与服务端需要保持同样的&#xff1b;半包粘包处理&#xff0c;编码解码处理、收发数据方式&#xff0c;这样才能保证数据通信正常。在前面NettyServer的章节中我们也同样处理了&#xff1b;半包粘包、编码解码等&#xff0c;为此在本章节我们…

Pikichu-xss实验案例-通过xss获取cookie

原理图&#xff1a; pikachu提供了一个pkxss后台&#xff1b; 该后台可以把获得的cookie信息显示出来&#xff1b; 查看后端代码cookie.php&#xff1a;就是获取cookie信息&#xff0c;保存起来&#xff0c;然后重定向跳转到目标页面&#xff1b;修改最后从定向的ip&#xff0…

PTH 实验

1. 实验网络拓扑 kali: 192.168.72.128win2008: 192.168.135.129 192.168.72.139win7: 192.168.72.149win2012:(DC) 192.168.72.131 2. EXPLOIT 0x0. NTLM hash计算脚本 python3 -c import hashlib,binascii; print (binascii.hexlify(hashlib.new("md4", "…

基于51单片机的3路电压测量-proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1PG2vzudc1QKHGSBfjPF0eQ 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

Leecode热题100-84.柱状图中的最大矩形

给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释&#xff1a;最大的矩形为图…

SQL SERVER 从嫌弃存储到爱上存储过程我给存储过程开发了版本控制工具和远程调试功能...

优缺点 SQL SERVER 爱上存储过程我给存储过程开发了版本控制工具和远程调试功能 先说说 存储过程的优缺点吧存储过程的优点 提高执行效率&#xff1a;存储过程是预编译的&#xff0c;执行速度较快&#xff0c;减少了网络传输量。 减少开发工作量&#xff1a;存储过程可以将复杂…

删除GitHub仓库的fork依赖 (Delete fork dependency of a GitHub repository)

解除fork仓库依赖的原因 在 Fork 了一个仓库&#xff0c;进行了大量修改&#xff0c;导致与父仓库的功能差异很大。 在每次 Pull Request 的默认目标分支是父仓库&#xff0c;很容易就会 PR 到父仓库里。 Fork 的仓库被其他人提出贡献并使用了&#xff0c;但不能显示贡献者…

【Python报错已解决】TypeError: not enough arguments for format string

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

国庆普及模拟2总结

目录 题目链接&#xff1a; 官方题解&#xff1a; 概述&#xff1a; 总结反思&#xff1a; 题目 T1: 题目分析&#xff1a; 错误代码&#xff1a; 错因&#xff1a; &#xff21;&#xff23;代码&#xff1a; T2&#xff1a; 题目分析&#xff1a; 赛时代码&#xf…

【Nacos架构 原理】内核设计之Nacos通信通道

文章目录 Nacos通信通道 &#xff08;长链接&#xff09;现状背景场景分析配置服务 长链接核心诉求功能性诉求负载均衡连接生命周期 Nacos通信通道 &#xff08;长链接&#xff09; 现状背景 Nacos 1.X 版本 Config/Naming 模块各自的推送通道都是按照自己的设计模型来实现的…

链表OJ经典题目及思路总结(二)头结点

系列文章目录 链表OJ经典题目及思路总结&#xff08;一&#xff09;双指针 链表OJ经典题目及思路总结&#xff08;二&#xff09;头结点 文章目录 系列文章目录前言1.建立新链表1.1 移除链表元素 2.哨兵位的头结点2.1 链表分割2.2 合并两个有序链表 3.CV工程师总结 前言 对于…

Python笔记 - 利用装饰器设计注解体系

认识注解 注解&#xff08;Annotation&#xff09;是一种用于为代码添加元数据的机制。这些元数据可以在运行时被访问&#xff0c;用于为代码元素&#xff08;如类、方法、字段等&#xff09;提供额外的信息或指示。 由于Python中装饰器只能装饰类和方法&#xff0c;因此也只…

C动态内存管理

前言&#xff1a;不知不觉又过去了很长的一段时间。今天对C语言中的动态内存管理进行一个系统性的总结。 1 为什么要有动态内存分配 在C语言中&#xff0c;使用int&#xff0c;float&#xff0c;double&#xff0c;short等数据内置类型以及数组不是也可以开辟内存空间吗&…

《算法岗面试宝典》重磅发布!

大家好&#xff0c;历时半年完善&#xff0c;《算法岗面试宝典》 终于可以跟大家见面了。 最近 ChatGPT 爆火&#xff0c;推动了技术圈对大模型算法场景落地的热情&#xff0c;就业市场招聘人数越来越多&#xff0c;算法岗一跃成为竞争难度第一的岗位。 岗位方向 从细分方向…