【数据结构高阶】并查集

目录

一、什么是并查集

二、并查集的原理

三、并查集的作用

四、并查集的代码实现


一、什么是并查集

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

 

二、并查集的原理

下面来看一个例子:某算法竞赛今年全国决赛总共有10人,4人来自西安,3人来自安徽,3人来自上海,10个人均来自不同的学校,起先互不相识,每个学生都是一个独立的小团体,现给这些学生进行编号:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

再用一个数组用来存储该小集体,数组下标表示学生的编号,数组中存储的数字我们先将其全部设为-1(为什么是-1下文会具体讲解):

竞赛时,每个地方的学生自发组织成小分队一起合作,于是:西安学生小分队s1={0,6,7,8},安徽学生小分队s2={1,4,9},上海学生小分队s3={2,3,5}就相互认识了,10个人形成了三个小团体。假设右三个群主0,1,2担任队长,负责组员的管理

这样子这10个学生就分成了三个组,我们用树的方式来表示一下:

下面我们使用双亲表示法,在之前建立的数组中进行三个小组的划分:

划分方法为:如果元素下标所表示的学生是组长不进行任何操作;如果下标所表示的学生是组员就将其下标的所对应的元素值加到所属组长的元素值上,再将自己的元素值改为组长所在元素下标:

这样处理过后我们可以发现:数组中存储的数字如果为负数,意味着该值所在的元素下标对应的学生是组长(树的根),其绝对值也代表该小集体中具有成员的个数(树的节点数);如果为不为负数,意味着该值所在的元素下标对应的学生是组员(树的叶子),其值也代表组长所在下标(指向自己的根)

按照上面的方法我们就可以使用数组来实现多棵树(森林)的表示了(和堆有点相似)

在比赛结束后,西安小分队中8号同学与安徽小分队4号同学奇迹般的走到了一起,两个小圈子的学生相互介绍,最后成为了以0号同学为主导的一个小圈子:

那树的形状发生了变化,数组对应的数据也会进行变化:

在数组中,一棵树要和另一棵树进行融合,先要找到要融合数据所对应的下标:例子里是4号同学,对应4号下标

再判断下标所在元素的数值,数值为正就继续找数值所对应的下标元素,一直找到数值为负的下标为止(找到要融合数据所在的根):先找到4号下标对应的数据是1,不是负数,那就继续找到1号下标所在的元素,其数值为-3,满足条件

最后将找到的根节点的数值加到另一棵树的根节点的数值上,再将其原本的根节点的数值改为另一棵树的根节点的下标:

现在0集合有7个人,2集合有3个人,总共两个朋友圈。

 

三、并查集的作用

通过以上例子可知,并查集一般可以解决一下问题:

1. 查找元素属于哪个集合,沿着数组表示树形关系以上一直找到根(即:树中中元素为负数的位置)

2. 查看两个元素是否属于同一个集合,沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在

3. 将两个集合归并成一个集合,将两个集合中的元素合并,将一个集合名称改成另一个集合的名称

4. 集合的个数遍历数组,数组中元素为负数的个数即为集合的个数。

 

四、并查集的代码实现

#include<iostream>
#include<vector>using namespace std;class UnionFindSet
{
public:int FindRoot(int n)//查找元素的根节点{int parent = n;while (_ufs[parent] >= 0){parent = _ufs[parent];}return parent;}void Union(int x, int y)//合并两个元素所在树{int root1 = FindRoot(x);int root2 = FindRoot(y);if (root1 == root2)//元素所在树都一样就没必要合并了return;if (root1 > root2)//取较小值的根节点来合并swap(root1, root2);_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}bool InSet(int x, int y)//判断两个元素是否在同一棵树{return FindRoot(x) == FindRoot(y);}size_t SetSize()//返回并查集中树的个数{size_t size = 0;for (auto e : _ufs){if (e < 0)++size;}return size;}private:vector<int> _ufs;
};

上述的代码实现的只是一个基本的并查集,如果并不想用元素下标来直接表示数据类型,我们可以使用map来建立对应的映射关系

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

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

相关文章

【LeetCode每日一题】【BFS模版与例题】【二维数组】1293. 网格中的最短路径

BFS基本模版与案例可以参考&#xff1a; 【LeetCode每日一题】【BFS模版与例题】863.二叉树中所有距离为 K 的结点 【LeetCode每日一题】【BFS模版与例题】【二维数组】130被围绕的区域 && 994 腐烂的橘子 思路&#xff1a; 特殊情况&#xff1a; 最短的路径是向下再向…

【电路笔记】-双极晶体管

双极晶体管 文章目录 双极晶体管1、概述2、双极晶体管结构3、双极晶体管配置3.1 共基极 (CB) 配置3.2 共发射极 (CE) 配置3.3 共集极 (CC) 配置4、总结1、概述 双极结型晶体管是一种可用于开关或放大的半导体器件。 与半导体二极管不同,半导体二极管由两片半导体材料组成,形…

【Java基础面试题2】

目录 前言 1.11 int和Integer有什么区别&#xff0c;二者在做运算时会得到什么结果&#xff1f; 1.12 说一说你对面向对象的理解 1.13 面向对象的三大特征是什么&#xff1f; 1.14 封装的目的是什么&#xff0c;为什么要有封装&#xff1f; 1.15 说一说你对多态的理解 1…

ElasticSearch|ES|架构介绍|原理浅析

架构介绍 节点 (Nodes): Elasticsearch 集群由多个节点组成&#xff0c;每个节点是一个独立运行的 Elasticsearch 实例。节点之间通过内部通信协议相互协作。 Master Node: 主节点负责管理集群范围的操作&#xff0c;例如创建或删除索引、分配和重新分配分片、维护集群状态等。…

StarUML6.0.1使用

1. 简介 作为一个软件开发人员&#xff0c;平时免不了做一定的软件设计&#xff0c;标准做法就是采用UML来设计&#xff1a; 讨论功能流程时采用时序图、活动图来表达&#xff1b;做业务功能架构时采用组件图来表达&#xff1b;做系统部署架构时采用部署图来表达&#xff1b;做…

因implements Interface书写顺序导致的Dubbo翻车实录

今天迁移Dubbo的代码&#xff0c;突然有个Service死活都找不到。 调用端报错&#xff1a; No provider available for the service org.ccframe.subsys.core.service.ITenantSearchService from registry 127.0.0.1:2181 on the consumer 192.168.1.88 using the dubbo version…

HTTPS如何保证数据传输的安全性 以及CA签发证书验签

暴力输出&#xff1a; 越看会越深入&#xff0c;睡前难以想通&#xff0c;后深入研究。得之。 有问题 请留言。 ----------追求内心的富足与平和。日行一善。 亓苏姑娘

Ollama--本地大语言模型LLM运行专家

文章目录 1、问题提出2、解决方案3、Ollama介绍3.1、Ollama的核心功能3.2、Ollama的独特之处 4、Ollama安装与使用4.1、Ollama的安装 5、使用Docker6、模型库和自定义模型7、应用场景展望8、结语 1、问题提出 使用chatgpt之类的闭源大语言模型时&#xff0c;我们与ai沟通的数据…

I.MX6ULL_Linux_驱动篇(54)linux 块设备驱动

前面我们都是在学习字符设备驱动&#xff0c;本章我们来学习一下块设备驱动框架&#xff0c;块设备驱动是Linux 三大驱动类型之一。块设备驱动要远比字符设备驱动复杂得多&#xff0c;不同类型的存储设备又对应不同的驱动子系统&#xff0c;本章我们重点学习一下块设备相关驱动…

【控制台警告】npm WARN EBADENGINE Unsupported engine

今天用webpack下载几个loader依赖&#xff0c;爆出了三个警告&#xff0c;大概的意思就是本地安装的node和npm的版本不是很匹配&#xff1f; 我的解决思路是&#xff1a; 先检查node和npm版本 然后去官网查找版本的对应 靠&#xff0c;官网404 Node.js (nodejs.org) 就找到…

操作系统:初识操作系统

目录 1.冯诺依曼体系结构 2.操作系统 2.1什么是操作系统 2.2为什么需要操作系统 2.3怎么实现操作系统 1.冯诺依曼体系结构 对于上图&#xff1a; 输入设备完成的是写入工作&#xff0c;输出设备完成输出工作&#xff0c;这两部分包含磁盘这类的外存。 存储器一般指的是内存…

Win UI3开发笔记(四)设置主题续2

本机深色主题下设置的背景颜色可以作用于整个对话框&#xff0c;本机浅色模式下设置的背景颜色只作用与下边的部分。 如果本机选深色&#xff0c;程序选浅色&#xff0c;设置为light只对上部分管用&#xff0c;下部分不管用。如图&#xff0c;左边那个hello按钮要看不见了。。…

协同办公大战再起,钉钉、飞书“决战”AI

对众多职场人来说&#xff0c;相信其对于钉钉、飞书、企业微信这些名字一定不会感到陌生&#xff0c;因为在当下的工作过程中&#xff0c;无论是考勤打卡&#xff0c;还是团队沟通协作&#xff0c;都离不开这些办公软件。而这些协同办公软件的出现&#xff0c;也为职场人的工作…

django学习记录06-Ajax的初识

Ajax请求 1.1Ajax请求与get、post请求的区别 form请求&#xff1a;浏览器向网站发送请求时&#xff0c;url和表单的形式提交 GET请求&#xff1a;url方式获取数据POST请求&#xff1a;以表单的形式提交数据 特点: 一次完整的GET或POST请求&#xff0c;会进行一次页面刷新 基于…

183基于matlab的非线性调频模态分解(VNCMD)

基于matlab的非线性调频模态分解(VNCMD)&#xff0c;一种基于变分方法的信号分解技术&#xff0c;它将信号分解为多个模式。能够处理非线性调频信号&#xff0c;且对噪声具有较好的鲁棒性。VNCMD的基本原理是通过最小化信号与模式之间的差异来实现信号的分解。程序已调通&#…

Latte:一个类似Sora的开源视频生成项目

前段时间OpenAI发布的Sora引起了巨大的轰动&#xff0c;最长可达1分钟的高清连贯视频生成能力秒杀了一众视频生成玩家。因为Sora没有公开发布&#xff0c;网上对Sora的解读翻来覆去就那么多&#xff0c;我也不想像复读机一样再重复一遍了。 本文给大家介绍一个类似Sora的视频生…

最简单的基于 FFmpeg 的 AVDevice 例子(屏幕录制)

最简单的基于 FFmpeg 的 AVDevice 例子&#xff08;屏幕录制&#xff09; 最简单的基于 FFmpeg 的 AVDevice 例子&#xff08;屏幕录制&#xff09;简介libavdevice 使用抓屏方法gdigrabdshow 源程序结果工程文件下载参考链接 最简单的基于 FFmpeg 的 AVDevice 例子&#xff08…

ASUS华硕天选2锐龙版笔记本电脑FA506ICB/FA706IC原装出厂Windows11系统,预装OEM系统恢复安装开箱状态

链接&#xff1a;https://pan.baidu.com/s/122iHHEOtNUu4azhVPnxNuA?pwdsqk7 提取码&#xff1a;sqk7 适用型号&#xff1a; FA506IM、FA506IE、FA506IC、FA506IHR FA506IR、FA506IHRB、FA506ICB、FA506IEB FA706IM、FA706IE、FA706IC、FA706IHR FA706IR、FA706IHRB、F…

FFmpeg【SDK02】关于AVIO的一些使用

读取本地文件&#xff08;网络流&#xff09;信息 #include <iostream> #include <stdio.h>extern "C" { #include <libavformat\avformat.h> #include <libavutil\avutil.h> #include <libavutil\log.h> #include <libavformat\a…

CSS的浮动属性,微信web开发

面试前的准备 在这部分&#xff0c;我将详细讲解面试前我们需要做哪些方面的工作&#xff0c;以保证我们在面试过程中更加顺利。 准备一份漂亮的简历 一份漂亮的简历就是你进入大厂的敲门砖。 网上有很多教程教大家如何写出一份漂亮的简历&#xff0c;这里我就不做重复劳动了…