【数据结构与算法-高阶】并查集

news2024/10/10 0:17:28

【数据结构与算法-高阶】并查集

🥕个人主页:开敲🍉

🔥所属专栏:数据结构与算法🍅

🌼文章目录🌼

1. 并查集原理

2. 并查集实现

3. 并查集应用

1. 并查集原理

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

  比如:某公司今年校招全国总共招生10人,西安招 4 人,成都招 3 人,武汉招 3 人,10 个人都来自不同的学校,开始互不相识,每个学生都是独立的小团体,现在我们给这些学生编号: {0,1,2,3,4,5,6,7,8,9};给定一下数组用来存储这些学生的编号,数组中存储的值暂且先别管,后面再解释:

  毕业后,这些学生去到了这家公司,西安、成都、武汉的学生都各自组成了一个小团体前往公司:西安小分队s1 = {0,6,7,8},成都小分队s2 = {1,4,9},武汉小分队s3 = {2,3,5}。假设 0、1、2分别是三个小分队的队长。

  在一趟漫长的火车旅行之后,小分队里的人都熟络了起来,成为了一个朋友圈:

  此时这个朋友圈在数组中的形式就变成了这样(还是先别管数组中存储的值的意义,后面会解释):

  从上图就可以清晰明白:编号 6、7、8的同学属于 0号 的小队;编号4、9的同学属于 1号 的小队;编号3、5的同学属于 2号 的小队。

  此时我们仔细观察一下数组中的值加以思考就能得出以下结论:

① 数组的下标就是同学的编号

② 数组中为负数的值所对应的下标就是队长的编号,我们在这里称之为  

③ 数组中所有为非负数的值也是队长的编号,也就是非负数的值指向根

  在公司工作了一段时间后,西安小分队中的8号同学与成都小分队的1号同学关系变得越来越亲密,经过这两位同学的相互介绍,西安小分队和成都小分队最终融合成了一个圈子:

  此时数组也变换成:

  现在0号的队伍中有了7个人,2号的队伍中有2个人,总共两个朋友圈,也可以说,总共两个根。

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

① 查找元素属于哪个集合:沿着该元素位置所存储的值一路跳转查找,直到遇到存储的值为负数的下标,就是集合的 根

② 查看两个元素是否属于同一个集合:依旧是跳转查找到存储的值为负数的下标,判断两个元素是否指向同一个根

③ 将两个集合归并为一个集合

④ 判断集合的个数

2. 并查集实现
//并查集
template <class T>
class Union
{
public:
	Union(size_t n)
		:_a(n,-1)
	{}

	//并集
	void UnionCom(size_t x,size_t y)
	{
		//寻找x、y所在集合的根,用root1、root2接收
		int root1 = FindRoot(x);
		int root2 = FindRoot(y);
		if (root1 == root2) return;//如果两个元素在同一个集合,则无需合并,直接返回

		_a[root1] += _a[root2];//将 root2 存储的值存入 root1 中
		_a[root2] = root1;//将 root2 归并到 root1下
	}

	//寻根
	int FindRoot(size_t x)
	{
		int flag = x;
		while (_a[flag] >= 0) flag = _a[flag];//沿着存储的值一路查找,直到找到存储的值为负数的下标
		return flag;
	}

	//求集合个数
	size_t UnionCount()
	{
		size_t count = 0;
		for (int i = 0; i < _a.size(); i++)
		{
			if (_a[i] < 0) count++;//存储的值是负数的就是集合的根
		}
		return count;
	}

	//判断是否在同一集合中
	bool UnionSam(size_t x, size_t y)
	{
		return (_a[x] == _a[y] && _a[x] != -1);
	}

private:
	vector<int> _a;
};
3. 并查集应用

下面题目的题解在:【每日刷题】Day134-CSDN博客 中。

LCR 116. 省份数量 - 力扣(LeetCode)

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) 
    {
        int ans = 0;
        vector<int> ufs(isConnected.size(),-1);

        auto findRoot = [&ufs](int x)
        {
            while(ufs[x]>=0) x = ufs[x];
            return x;
        };

        for(int i = 0;i<isConnected.size();i++)
        {
            for(int j = 0;j<isConnected[i].size();j++)
            {
                if(isConnected[i][j])
                {
                    int root1 = findRoot(i);
                    int root2 = findRoot(j);
                    if(root1!=root2)
                    {
                        ufs[root1]+=ufs[root2];
                        ufs[root2] = root1;
                    }
                }
            }
        }
        for(int i = 0;i<ufs.size();i++)
        {
            if(ufs[i]<0) ans++;
        }
        return ans;
    }
};

990. 等式方程的可满足性 - 力扣(LeetCode)

class Solution {
public:
    bool equationsPossible(vector<string>& equations) 
    {
        vector<int> ufs(26,-1);

        auto findRoot = [&ufs](int x)
        {
            while(ufs[x]>=0) x = ufs[x];
            return x;
        };

        //相等放入同一集合
        for(auto str:equations)
        {
            if(str[1]=='=')
            {
                int root1 = findRoot(str[0]-'a');
                int root2 = findRoot(str[3]-'a');
                if(root1!=root2)
                {
                    ufs[root1]+=ufs[root2];
                    ufs[root2] = root1;
                }
            }
        }

        //不相等判断是否在同一个集合,如果在则相悖
        for(auto str:equations)
        {
            if(str[1]=='!')
            {
                int root1 = findRoot(str[0]-'a');
                int root2 = findRoot(str[3]-'a');
                if(root1==root2) return false;
            }
        }
        
        return true;
    }
};

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

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

相关文章

Matlab|基于遗传粒子群算法的无人机路径规划【遗传算法|基本粒子群|遗传粒子群三种方法对比】

目录 主要内容 模型研究 部分代码 结果一览 下载链接 主要内容 为了更高效地完成复杂未知环境下的无人机快速探索任务&#xff0c;很多智能算法被应用于无人机路径规划方面的研究&#xff0c;但是传统粒子群算法存在粒子更新思路单一、随机性受限、收敛速度慢…

修改calibre-web最大文件上传值

修改calibre-web最大文件上传值 Windows安装calibre-web&#xff0c;Python-CSDN博客文章浏览阅读541次&#xff0c;点赞10次&#xff0c;收藏11次。pip install calibreweb报错&#xff1a;error: Microsoft Visual C 14.0 or greater is required. Get it with "Microso…

案例:问题处理与原因分析报告的模板

系统上线后暴露的问题也是一种财富&#xff0c;我们需要从中吸收经验教训&#xff0c;规避其他类似的问题。对于上线后的问题如何进行原因分析&#xff0c;我提供两个分析报告的模板&#xff0c;供大家参考。 模板案例1&#xff1a;共性现象的原因分析报告 模板案例二&#xf…

C(十三)for、while、do - while循环的抉择 --- 打怪闯关情景

前言&#xff1a; 继C&#xff08;十&#xff09;for循环 --- 黑神话情景之后&#x1f449; https://blog.csdn.net/2401_87025655/article/details/142684637 今天&#xff0c;杰哥想用一个打怪闯关的场景让与大家一起初步认识一下for、while、do - while循环的抉择。&#xf…

Docker在linux系统中的下载与使用

Docker在linux系统中的下载与使用 一、docker作用,下载及安装二、docker镜像三、创建容器四、容器数据卷 一、docker作用,下载及安装 ubuntu下载安装docker 命令&#xff1a;在ubuntu上面执行这个命令 Docker version:查看docker是否安装成功 配置阿里云镜像加速:进入阿里云网站…

阿里140滑块-滑块验证码逆向分析思路学习

一、声明&#xff01; 原创文章&#xff0c;请勿转载&#xff01; 本文内容仅限于安全研究&#xff0c;不公开具体源码。维护网络安全&#xff0c;人人有责。 文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;均已做脱敏处…

JUC高并发编程8:读写锁

1 概述 1.1 悲观锁和乐观锁 在并发编程中&#xff0c;锁机制是用来控制多个线程对共享资源的访问。悲观锁和乐观锁是两种不同的并发控制策略。 1.1.1 悲观锁&#xff08;Pessimistic Locking&#xff09; 悲观锁假设在最坏的情况下&#xff0c;多个线程会同时访问和修改共享…

Qt-QDockWidget浮动窗口相关操作(49)

目录 描述 使用 描述 在 Qt 中&#xff0c;浮动窗⼝也称之为铆接部件。浮动窗⼝是通过 QDockWidget类 来实现浮动的功能。浮动窗口⼀般是位于核心部件的周围&#xff0c;可以有多个。 使用 创建我们可以参考下面的语法格式 使用起来也很简单&#xff0c;不过只能创建一个 Q…

【C语言】使用结构体实现位段

文章目录 一、什么是位段二、位段的内存分配1.位段内存分配规则练习1练习2 三、位段的跨平台问题四、位段的应用五、位段使用的注意事项 一、什么是位段 在上一节中我们讲解了结构体&#xff0c;而位段的声明和结构是类似的&#xff0c;它们有两个不同之处&#xff0c;如下&…

创建osd加入集群

故障原因&#xff1a;ceph节点一个磁盘损坏&#xff0c;其中osd69 down了&#xff0c;需要更换磁盘并重新创建osd加入ceph集群。 信息采集&#xff1a; 更换磁盘前&#xff0c;查询osd69对应的盘符&#xff1a; 将对应的故障磁盘更换后&#xff0c;并重做raid&#xff0c;然后查…

SDK4(note下)

以下代码涉及到了很多消息的处理&#xff0c;有些部分注释掉了&#xff0c;主要看代码 #include <windows.h> #include<tchar.h> #include <stdio.h> #include <strsafe.h> #include <string> #define IDM_OPEN 102 /*鼠标消息 * 键盘消息 * On…

76.【C语言】perror函数介绍

1.cplusplus的官网介绍 cplusplus的介绍 点我跳转 2.翻译 函数 perror void perror ( const char * str ); 打印错误信息 将errno(最后一个错误数字)的值解释为错误信息,之后把它打印到stderr中(标准错误输出流,通常是控制台)(备注有关"流"的概念在75.【C语言】文件…

k8s-pod的管理及优化设置

Pod是Kubernetes&#xff08;k8s&#xff09;中最小的资源管理组件&#xff0c;也是最小化运行容器化应用的资源对象。以下是对Pod的详细介绍&#xff1a; 一、Pod的基本概念 定义&#xff1a;Pod是Kubernetes中可以创建和管理的最小单元&#xff0c;是资源对象模型中由用户创…

网站排名,让网站快速有排名的几个方法

要让网站快速获得并提升排名&#xff0c;需要综合运用一系列专业策略和技术&#xff0c;这些策略涵盖了内容优化、技术调整、外链建设、用户体验提升等多个方面。以下是让网站快速有排名的几个方法&#xff1a; 1.内容为王&#xff1a;创造高质量、有价值的内容 -深入…

geolocator插件的用法

文章目录 1. 概念介绍2. 使用方法3. 示例代码4 体验分享我们在上一章回中介绍了如何实现滑动菜单相关的内容,本章回中将介绍如何获取位置信息.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在这里说的获取位置信息本质上是获取当前手机所在位置的gps坐标,就是我们…

【Chrome浏览器插件--资源嗅探猫抓】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、资源嗅探插件---猫抓二、使用步骤总结 一、资源嗅探插件—猫抓 猫抓是一个浏览器插件&#xff0c;可以检测当前网页中的一些资源文件&#xff0c;可设置嗅探的…

NVIDIA机密计算文档

NVIDIA 可信计算解决方案 文章目录 前言一、指南1. Intel TDX - 机密计算部署指南2. AMD SNP - 机密计算部署指南3. NVIDIA Hopper 机密计算证明文档4. nvtrust GitHub二、发行说明1. 550TRD3 - NVIDIA 可信计算解决方案发行说明2. 550TRD1 - NVIDIA 可信计算解决方案发行说明三…

The Android SDK location cannot be at the filesystem root

win11&#xff0c; 安装启动完Android Studio后&#xff0c;一直显示 The Android SDK location cannot be at the filesystem root因此需要下载SDK包&#xff0c;必须开启代理。 开启代理后&#xff0c;在System下开启自动检测代理&#xff0c;如图 重启Android Studio&a…

任务【浦语提示词工程实践】

0.1 环境配置 首先点击左上角图标&#xff0c;打开Terminal&#xff0c;运行如下脚本创建虚拟环境&#xff1a; # 创建虚拟环境 conda create -n langgpt python3.10 -y 运行下面的命令&#xff0c;激活虚拟环境&#xff1a; conda activate langgpt 之后的操作都要在这个环境…

基于LORA的一主多从监测系统_0.96OLED

关联&#xff1a;0.96OLED hal硬件I2C LORA 在本项目中每个节点都使用oled来显示采集到的数据以及节点状态&#xff0c;OLED使用I2C接口与STM32连接&#xff0c;这个屏幕内部驱动IC为SSD1306&#xff0c;SSD1306作为从机地址为0x78 发送数据&#xff1a;起始…