【高阶数据结构(一)】并查集详解

news2024/9/24 19:24:12

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:高阶数据结构专栏⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习更多Go语言知识
  🔝🔝


在这里插入图片描述

高阶数据结构

  • 1. 前言
  • 2. 并查集的原理
  • 3. 并查集的实现
  • 4. 并查集的应用
  • 5. 总结以及拓展

1. 前言

本系列会带大家走进高阶数据结构的学习, 其中包括并查集,图论, LRU cache, B树, B+树, B*树, 跳表. 其中, 图论中讲解的时间最长, 包括邻接表, 邻接矩阵, 广度优先遍历, 深度优先遍历, 最小生成树, 以及prim算法, dijkstra算法, bellman-Ford算法, Floyd-wars hall算法. 高阶数据结构属于拓展内容, 建议把基础掌握好后再学

本章重点:

本篇文章着重讲解并查集的原理, 并查集的实现(CPP),以及并查集的应用


2. 并查集的原理

在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-find set)。

比如, 公司招的10个人当中有4人是北京的,三人是上海的,3人是深圳的. 那么他们就可以被分为三个不同的集合. 现在将他们进行编号(0~9),然后来看看如何将他们进行分组(为什么初始值为-1,后面再解释)

在这里插入图片描述

北京学生: 0,6,7,8.上海学生: 1,4,9.深圳学生: 2,3,5
假如选出0,1,2号学生作为小组的组长

在这里插入图片描述

现在需要在数组中,表示三个分组, 不卖关子,直接讲解并查集的原理. 当组长的人的位置的值是负数,-n代表这个组有n个人. 而非组长的成员的位置的值存储的是组长的下标,这样说可能有点抽象,下面来画个图看看

在这里插入图片描述

北京小组的组长是0,它的值是-4代表此小组有四个人.6,7,8是0的组员,所以它们存储的值是0,也就是组长的下标. 所以刚开始初始值为-1,代表每一个数都自成一个集合

现在出现一个情况, 由于北京的同学和上海的同学经常在一起玩耍, 所以久而久之他们就很熟了,就想着将这两个分组合并.于是出现了以下的情况:

在这里插入图片描述

此时,下标为1的位置应该存储它的父亲,也就是0,下标为4.9的位置不能直接存储0,而是应该存储1,因为1才是他们的直系父亲. 可以用下图来表示:

在这里插入图片描述

你可以窥探到,下标为0的值从-4变为-7,而下标为1的值从-3变为0,实际上就为我们后面的手撕并查集提供了思路


3. 并查集的实现

在进行并查集实现时,应该要拥有这几个基础功能函数: 找到一个下标的根, 合并两个集合, 判断两个树是否在同一个集合. 计算此并查集一共有几个集合.

并查集的本质是数组,所以可以这样定义结构:

class UnionFindSet
{
public:
	UnionFindSet(size_t n):_ufs(n,-1)//初始化数组,初始值设为-1
private:
	vector<int> _ufs;	
};

首先可以先实现,找到一个下标的根,后续的函数可以复用它:

int FindRoot(int x)//找到一个下标的根
{
	int parent = x;
	while (_ufs[parent] >= 0)
		parent = _ufs[parent];
	//路径压缩.下次查找时效率就高了(压缩当前节点以及它的父亲节点)
	while (_ufs[x] >= 0)
	{
		int tmp = _ufs[x];
		_ufs[x] = parent;
		x = tmp;
	}
	return parent;
}

这份代码可以分为两步,第一步就是在找它的根,就是一直向前找直到遇见负数.第二部分的代码在进行路径压缩工作,若是有多个集合进行合并,那么我们的树可能就会很高,查找最下面的树的根时,就会出现效率低下的问题,所以进行路径压缩很有必要. 关于路径压缩的原理如下:

在这里插入图片描述
下次再查找4的时候,就优化了时间

接下来的代码就简单了:

#pragma once
#include<vector>
#include<iostream>
using namespace std;
class UnionFindSet
{
public:
	UnionFindSet(size_t n):_ufs(n,-1)
	{}
	void Union(int x1, int x2) //合并两个集合
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);
		if (root1 == root2) return;
		if (_ufs[root1] < _ufs[root2])
		{
			_ufs[root1] += _ufs[root2];
			_ufs[root2] = root1;
		}
		else
		{
			_ufs[root2] += _ufs[root1];
			_ufs[root1] = root2;
		}
	}
	int FindRoot(int x)//找到一个下标的根
	{
		int parent = x;
		while (_ufs[parent] >= 0)
			parent = _ufs[parent];
		//路径压缩.下次查找时效率就高了(压缩当前节点以及它的父亲节点
		while (_ufs[x] >= 0)
		{
			int tmp = _ufs[x];
			_ufs[x] = parent;
			x = tmp;
		}
		return parent;
	}
	bool SameSet(int x1, int x2)//判断这两个数是否在同一个集合
	{
		return FindRoot(x1) == FindRoot(x2);
	}
	size_t SetSize()//这个并查集一共有几个集合
	{
		size_t size = 0;
		for (auto x : _ufs)
			if (x < 0)
				size++;
		return size;
	}
private:
	vector<int> _ufs;	
};

判断两个数是否在同一集合,以及一共有几个集合,这两个函数比较简单,不做讲解. 合并两个集合先要找到这两个数的根,如果这两个数有相同的根就直接返回,否则就开始合并.合并的逻辑也非常简单,其中的if,else语句不是必须的


4. 并查集的应用

由于我是学生,所以我先给大家看看并查集在校招中考察的多不多,这道题: 省份数量是19年美团笔试的原题,并且今年24年的笔试疑似也出现过并查集解题. 除此之外, 华为考察算法和数据结构也比较厉害.其中的考点之一就有并查集:

在这里插入图片描述

并查集往往用于解决图上的问题,并查集只有两个操作,“并” 和 “查”,但是通过这两个操作可以派生出一些其他的应用:

  • 图的连通性问题
  • 集合的个数
  • 集合中元素的个数

并且在后面学习图论的过程中,也会涉及到并查集的知识,会复用并查集的代码. 这也是我优先讲并查集的原因之一, 如果你没有学过并查集直接去搞图论,可能会十分吃力


5. 总结以及拓展

并查集只是高阶数据结构中的开胃菜,后面的数据结构会越来越难,请大家耐心学习


🔎 下期预告:图论 🔍

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

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

相关文章

【vue+echarts】绘制中国地图,3D地图,省、市、县三级下钻以及回钻,南海诸岛小窗化显示,点位飞线图,点位名称弹窗轮播展示,及一些常见问题

先看效果展示图 目录 准备工作一, 绘制3D地图1,调用官网地址接口获取2,去官网下载中国地图的json数据到本地,本地引入 二, 南海诸岛小窗化显示1, 手动过滤掉,只保留小窗化的南海诸岛2, 代码层面过滤掉,只保留小窗化的南海诸岛 三, 省、市、县三级地图下钻及回钻1, 下钻2, 回钻…

深度学习 --- stanford cs231学习笔记(一)

stanford cs231学习笔记(一) 1&#xff0c;先是讲到了机器学习中的kNN算法&#xff0c;然后因为kNN分类器的一些弊端&#xff0c;引入了线性分类器。 kNN算法的三大弊端&#xff1a; (1)&#xff0c;计算量大&#xff0c;当特征比较多时表示性差 (2)&#xff0c;训练时耗时少…

C++初阶之模板初阶

一、泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left right;right temp; } void Swap(char& left,…

sql编写规范(word原件)

编写本文档的目的是保证在开发过程中产出高效、格式统一、易阅读、易维护的SQL代码。 1 编写目的 2 SQL书写规范 3 SQL编写原则 软件全套资料获取进主页或者本文末个人名片直接获取。

[Java、Android面试]_22_APP启动流程(中频问答)

欢迎查看合集&#xff1a; Java、Android面试高频系列文章合集 本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&am…

偏微分方程算法之混合边界条件下的差分法

目录 一、研究目标 二、理论推导 三、算例实现 四、结论 一、研究目标 我们在前几节中介绍了Poisson方程的边值问题&#xff0c;接下来对椭圆型偏微分方程的混合边值问题进行探讨&#xff0c;研究对象为&#xff1a; 其中&#xff0c;为矩形区域&#xff0c;为上的连续函数…

毕业设计参考-PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序,OpenCV、Modbus通信、YOLO目标检测综合应用

“PyQt5-YOLOv8-鱼头鱼尾鱼长测量程序”是一个特定的软件程序&#xff0c;用于通过图像处理和目标检测技术来测量鱼类的长度。 视频效果&#xff1a; 【毕业设计】基于yolo算法与传统机器视觉的鱼头鱼尾识别_哔哩哔哩_bilibili 这个程序结合了多种技术&#xff1a; 1. OpenCV…

【数据结构(邓俊辉)学习笔记】列表03——有序列表

文章目录 0. 概述1. 唯一化2. 查找2.1 实现2.2 顺序查找2.3 复杂度 0. 概述 介绍下有序列表。 若列表中所有节点的逻辑次序与其大小次序完全一致&#xff0c;则称作有序列表&#xff08;sorted list&#xff09;。为保证节点之间可以定义次序&#xff0c;依然假定元素类型T直接…

【一刷《剑指Offer》】面试题 12:打印 1 到最大的 n 位数

力扣对应题目链接&#xff1a;LCR 135. 报数 - 力扣&#xff08;LeetCode&#xff09; 牛客对应题目链接&#xff1a;打印从1到最大的n位数_牛客题霸_牛客网 (nowcoder.com) 一、《剑指Offer》内容 二、分析题目 1、暴力解法 2、用字符串模拟数字加法 首先要考虑当 n 很大时&…

Pandas层级索引

文章目录 第1关&#xff1a;多级索引的取值与切片第2关&#xff1a;多级索引的数据转换与累计方法 第1关&#xff1a;多级索引的取值与切片 编程要求 本关的编程任务是补全右侧上部代码编辑区内的相应代码&#xff0c;要求实现如下功能&#xff1a; 使用MultiIndex创建如下Da…

Vue3+.NET6前后端分离式管理后台实战(十七)

1&#xff0c;Vue3.NET6前后端分离式管理后台实战(十七)已经在微信公众号更新&#xff0c;有兴趣的扫码关注一起交流学习。

ShardingSphere 5.x 系列【30】影子库

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 影子库与全链路压测2. 核心概念3. 使用限制4. 执行原理4.1 DML 语句4.2 D…

Vue前端环境准备

vue-cli Vue-cli是Vue官方提供的脚手架&#xff0c;用于快速生成一个Vue项目模板 提供功能&#xff1a; 统一的目录结构 本地调试 热部署 单元测试 集成打包上线 依赖环境&#xff1a;NodeJs 安装NodeJs与Vue-Cli 1、安装nodejs&#xff08;已经安装就不用了&#xff09; node-…

指挥中心操作台的选择至关重要

在指挥中心的环境中&#xff0c;操作台是核心设备&#xff0c;它承载着信息收集、处理、分发的重要任务。其选择应考虑到多方面的因素&#xff0c;包括外观、材质、稳定性、操作便利性以及技术支持等。嘉德立在这里给大家详细的总结一下选择指挥中心操作台的要点。 首先&#x…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

Ansible之性能调优

有很多人说Ansible的执行效率比SaltStack差&#xff0c;确实&#xff0c;默认使用的SSH方式通信&#xff0c;效率远低于SaltStack的zeromq消息队列。但是我们可以优化Ansible的执行速度&#xff0c;可以做到并不比SaltStack差。 1. 开启SSH长连接 在OpenSSH 5.6版本后&#xf…

【Proteus】LED呼吸灯 直流电机调速

1.LED呼吸灯 #include <REGX51.H> sbit LEDP2^0; void delay(unsigned int t) {while(t--); } void main() {unsigned char time,i;while(1){for(time0;time<100;time){for(i0;i<20;i){LED0;delay(time);LED1;delay(100-time);}}for(time100;time>0;time--){fo…

【软件测试理论002】认识软件缺陷、缺陷生命周期、缺陷分类

目录 1 认识软件缺陷 1.1 什么是软件缺陷 1.2 缺陷存在哪些方面 1.3 软件缺陷示例 1.4 软件缺陷的表现形式 1.5 软件缺陷产生的原因 1.6 软件缺陷的根源 1.7 软件缺陷修复的费用 2 软件缺陷的信息分类 2.1 软件缺陷的生命周期 2.2 软件缺陷的信息 2.3 软件缺陷分类…

论文| What makes visual place recognition easy or hard?

论文| What makes visual place recognition easy or hard?

【C语言】简单有趣的扫雷游戏

**©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 一、分析游戏规则二、分文件三、菜单实现四、游戏内容核心实现1.初始化棋盘2.打印棋盘3.布置雷4.排查雷5.game()函数实现调用 五、全部源码 一、分…