并查集(C++实现)

news2024/9/28 9:32:17

目录

一、并查集原理

二、并查集应用

2.1 并查集举例

2.2 并查集数组规律

2.3 并查集功能

三、并查集实现

3.1 并查集

3.2 根据名字查找

四、例题

4.1 省份数量

4.2 等式方程的可满足性


一、并查集原理

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

  • 并查集并查集,就是看你在哪个集合中,并且可以将集合合并的数据结构

二、并查集应用

2.1 并查集举例

某公司今年招收10人,上海招收4人,成都招收3人,武汉招收3人;这10个人来自不同的学校,每个学生都是一个独立的小团体,现在给这些学生编号:{0,1,2,3,4,5,6,7,9};给以下数据用来存储该小集合,数组中的数据代表:该小集合中具有成员的个数:
在这里插入图片描述
毕业后,学生们要去公司上班,每个地方的学生自发组织成小分队一起上路,于是:
上海学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}就相互认识了,10个人形成了三个小团体。假设右三个群主0,1,2担任队长,负责大家的出行。
在这里插入图片描述
一趟火车之旅后,每个小分队成员就互相熟悉,成为了一个朋友圈。
在这里插入图片描述

从上图可以看出:
编号为6,7,8同学属于0号小分队,该小分队中有4人(包含队长0);
编号为4和9的同学属于1号小分队,该小分队有3人(包含队长1);
编号为3和5的同学属于2号小分队,该小分队有3人(包含队长1)。

2.2 并查集数组规律

此时数组中便会出现以下规律:

  1. 数组的下标对集合中元素的编号
  2. 数组中如果为负数,负号代表根,数字代表该集合中元素个数
  3. 数组中如果为非负数,代表该元素双亲在数组中的下标

在公司工作一段时间后,西安小分队中8号同学与成都小分队1号同学奇迹般地走到了一起,两个小圈子的同学相互介绍,最后成为了一个圈子:
在这里插入图片描述
现在0集合有7个人,2集合有3个人,总共有两个朋友圈。

2.3 并查集功能

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

  1. 查找元素属于哪个集合
    沿着数组表示树形关系以上一致找到根(即:树中元素为负数的位置)
  2. 查看两个元素是否属于同一个集合
    沿着数组表示的树形关系往上一直找到根,如果根相同表明在同一个集合,否则不在
  3. 两个集合归并成一个集合
    将两个集合中的元素合并
    将一个集合名称改为另一个集合的名称
  4. 集合的个数
    遍历数组,数组中元素为负数的个数即为集合的个数。

三、并查集实现

3.1 并查集

并查集需要有下面的接口

  • 查找元素属于哪个集合
  • 查看两个元素是否属于一个集合
  • 合并两个集合
  • 集合的个数

在这里插入图片描述


查找元素属于哪个集合


查看两个元素是否属于一个集合


合并集合

我们只能做到将一个集合合并到另一个集合,让其作为子集。

步骤(右集合合并至左集合):

1. 找到两个集合的根

2. 判断两个集合的根是否不同,相同则不做处理

3. 将右集合中记录集合数累加到左集合中。

4. 再将右集合指向左集合。



集合的个数

3.2 根据名字查找

这里我们可以实现一个根据名字查找编号。

实现思路:

        用一个数组来存放所有学生的信息,再使用map来建立映射关系。

map的使用<string, int>类型,根据名字查找到数组中该学生的下标,使用该下标再访问数组即可查到数据。

//学生信息数组
vector<student_info> arr{ student_info("Brant", 20, 10),
    student_info("James", 40, 70),
 student_info("Curry", 30, 100) };


//并查集
vector<student_info> UnionFind_arr(3);
map<string, int> UnionFind_map;

for (int i = 0; i < arr.size(); i++)
{
    UnionFind_arr[i] = arr[i];
    UnionFind_map[arr[i]._name] = i;
}


//可以通过名字找到编号
cout << "James信息的下标为:" << UnionFind_map["James"] << endl;
cout << UnionFind_arr[UnionFind_map["James"]] << endl;

 student_info类

class student_info
{
public:
        friend ostream& operator<<(std::ostream& os, const student_info& info);
        student_info(string name,int age,int score)
                :_name(name),_age(age),_score(score)
        {
        }
        string _name;
        int _age;
        int _score;
};

ostream& operator<<(std::ostream& os, const student_info& info)
{
        os << "Name: " << info._name << "\n"
                << "Age: " << info._age << "\n"
                << "Score: " << info._score << "\n";
        return os;
}

四、例题

我觉得,把这两道并查集的题目解决,才算学会了并查集。

4.1 省份数量

4.1 省份数量

解题思路:

        这个省份数量就类似我们本篇博客举的实习例子很像,是同一个集合,就将其合并到一起。最后通过统计有几个这样的集合即可。

只不过这题使用了二维数组来表达这种关系。

直接将我们编写的并查集类放入代码中,调用其中的函数即可通过。


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)
		{
			_ufs[root1] += _ufs[root2];
			_ufs[root2] = root1;
		}
	}
	int FindRoot(int x)
	{
		int root = x;
		while (_ufs[root] >= 0)
		{
			root = _ufs[root];
		}
		return root;
	}
	bool IsInset(int x1,int x2)
	{
		return FindRoot(x1) == FindRoot(x2);
	}
	size_t setSize()
	{
        size_t size=0;
        for(int i =0;i<_ufs.size();i++)
        {
            if (_ufs[i]<0)
                ++size;
        }
        return size;
    }
private:
	vector<int> _ufs;
};
class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        UnionFindSet ufs(isConnected.size());
        for(size_t i = 0;i<isConnected.size();i++)
            for(size_t j = 0;j<isConnected[i].size();j++)
                if (isConnected[i][j] == 1)
                    ufs.Union(i,j);

        return ufs.setSize();
    }
};

直接使用并查集思想一样可以写出来

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        vector<int> ufs(isConnected.size(),-1);
				auto findRoot = [&ufs](int x)
				{
					while(ufs[x]>=0)
						x=ufs[x];
						return x;
				};
        for(size_t i = 0;i<isConnected.size();i++)
        {
            for(size_t j = 0;j<isConnected[i].size();j++)
            {
							if (isConnected[i][j]==1)
							{
									int root1 =findRoot(i);
                int root2 =findRoot(j);
								if (root1!=root2)
								{
										ufs[root1] += ufs[root2];
										ufs[root2] = root1; 
								}
							}
               
            }
        }
			  size_t size=0;
        for(int i =0;i<ufs.size();i++)
        {
            if (ufs[i]<0)
                ++size;
        }
        return size;
				
    }
};

4.2 等式方程的可满足性

等式方程的可满足性

这一题我们首先处理相等

遍历数组,如果是相等,我们就将其归到同一个集合中,则表示该等式中的变量都是相等的。

然后我们再遍历数组中的不相等方程,找到两个变量的根,因为是不相等,则这两个变量肯定不在一个集合中,通过 find 如果发现两个变量是同一个根,则表示在同一个集合中,即方程不正确。

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;
            }
            }
        }
        //不相等公式,如果两个根在同一个集合则返回false
        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/929320.html

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

相关文章

Python读取Excel:实现数据高效处理的利器

目录 一、Python读取Excel的常用库二、Python读取Excel的步骤三、具体案例和使用场景四、Python读取Excel的优势与其他编程语言比较 摘要 本文将介绍Python读取Excel的方法&#xff0c;并通过具体案例和使用场景展示如何实现数据高效处理。我们将介绍常用的Python库&#xff0c…

QT基础使用:组件和代码关联(信号和槽)

自动关联 ui文件在设计环境下&#xff0c;能看到的组件可以使用鼠标右键选择“转到槽”就是开始组件和动作关联。 在自动关联这个过程中软件自动动作的部分 需要对前面头文件进行保存&#xff0c;才能使得声明的函数能够使用。为了方便&#xff0c;自动关联时先对所有文件…

【Hello Algorithm】堆和堆排序

本篇博客简介&#xff1a; 讲解堆和堆排序相关算法 堆和堆排序 堆堆的概念堆的性质堆的表示形式堆的增加删除堆的最大值 堆排序堆排序思路时间复杂度为N的建堆方法已知一个近乎有序的数组 使用最佳排序方法排序 堆 堆的概念 这里注意&#xff01;&#xff01;&#xff01; 这…

日志系统——性能测试

日志系统项目已经编写完成&#xff0c;在本节完成性能测试之后就正式结束了 测试代码如下 #include "../logs/mjwlog.h" #include <vector> #include <thread>//参数&#xff1a;日志器名称&#xff0c;线程数量&#xff0c;输出日志条数&#xff0c;单…

nginx(七十八)nginx配置http2

一 ngx_http_v2模块 1、本文不讲解HTTP2的知识2、只讲解nginx中如何配置HTTP2 ① 前置条件 1、openssl的版本必须在1.0.2e及以上2、开启https加密,目前http2.0只支持开启了https的网站编译选项&#xff1a;--with-http_ssl_module --with-http_v2_module 特点&#xff1a…

【翻译】RISC-V指令集手册第Ⅱ卷:特权体系结构

第三章 机器级ISA&#xff0c;版本1.11 本章描述RISC-V系统中最高权限的机器模式(M-mode)下的机器级操作。M模式用于对硬件平台的低级访问&#xff0c;是复位时进入的第一个模式。M模式还可以用于实现在硬件中直接实现过于困难或代价过高的特性。RISC-V机器级ISA包含一个公共核…

Android Studio升级到Android API 33版本后,XML布局输入没有提示

低版本的Android Studio升级到Android API 33版本后&#xff0c;XML布局输入没有提示。查一下我目前使用的Android Studio 是2021年发布&#xff0c;而Android API 33是2022年发布的&#xff0c;这是由低版本升级到高版本造成不兼容的问题。解决方法有两种&#xff1a; 第一种…

1 Hadoop入门

1.Hadoop是什么&#xff1f; (1)Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 (2)主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。 (3)广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念——Hadoop生态圈 2.Hadoop的优势 3 Hadoop组成 4 HDF…

如何将储存在Mac或PC端的PDF文件传输到移动设备呢?

iMazing是一款iOS设备管理软件&#xff0c;用户借助它可以将iPad或iPhone上的文件备份到PC或Mac上&#xff0c;还能实现不同设备之间的文件传输&#xff0c;能很大程度上方便用户进行文件管理。 在阅读方面&#xff0c;iPad和iPhone是阅读PDF的优秀选择&#xff0c;相较于Mac或…

IDEA常用配置之类Tab页多行显示

文章目录 IDEA常用配置之类Tab页多行显示 IDEA常用配置之类Tab页多行显示 默认在Idea中打开类过多&#xff0c;后面会隐藏显示&#xff0c;这里修改配置&#xff0c;将类设置为多行显示&#xff0c;方便查找已经打开的类 修改后显示样式

抢先体验|乐鑫推出 ESP32-S3-BOX-3 新一代开源 AIoT 开发套件

乐鑫科技 (688018.SH) 非常高兴地宣布其开发套件阵容的最新成员 ESP32-S3-BOX-3。这款完全开源的 AIoT 应用开发套件搭载乐鑫高性能 ESP32-S3 AI SoC&#xff0c;旨在突破传统开发板&#xff0c;成为新一代开发工具的引领者。 【乐鑫新品抢先体验】ESP32-S3-BOX-3 新一代开源 A…

ctfshow-web13 文件上传

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 首先看到是一个上传页面&#xff0c;测试其他无果&#xff0c;遂进行目录遍历&#xff0c;发现upload.php.bak文件 可以看到这里的限制条件&#xff0c;大小&#xff0c;以及内容&#xff0c;这里可以使用.use…

DataWhale夏令营第三期-CV赛道-第三次打卡

第三次打卡 使用resnet18训练精度&#xff1a;评分0.74 使用resnet34精度&#xff1a;评分0.74 使用resnet50精度&#xff1a;评分0.21&#xff0c;不知道为什么网络层数高反而准确度下降&#xff0c;猜测层数多丢失了一些特征信息。

数据结构入门 — 链表详解_双向链表

前言 数据结构入门 — 双向链表详解* 博客主页链接&#xff1a;https://blog.csdn.net/m0_74014525 关注博主&#xff0c;后期持续更新系列文章 文章末尾有源码 *****感谢观看&#xff0c;希望对你有所帮助***** 系列文章 第一篇&#xff1a;数据结构入门 — 链表详解_单链表…

【每日一题】1448. 统计二叉树中好节点的数目

【每日一题】1448. 统计二叉树中好节点的数目 1448. 统计二叉树中好节点的数目题目描述解题思路 1448. 统计二叉树中好节点的数目 题目描述 给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节…

微信小程序如何实现页面传参和页面传递多个参数

前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递&#xff0c;下面我总结了 4 种页面方法。 下面时多个参数页面传参的方式 let loveJSON.stringify(this.data.totle);let youJSON.stringify(this.data.totleId)let csdnJSON.stringify(this.data.totleP…

命令全局安装 ts

1.全局安装 typeScript编译 npm install -g typescript2.查看版本 tsc-v安装成功的画面

win10+wsl2+Ubuntu20.2+Pycharm+WSL解释器

目的&#xff1a;创建一个ubuntu系统下的python解释器&#xff0c;作为win平台下的pycharm的解释器。 这样做的好处是可以直接在win系统里操作文件&#xff0c;相比于linux方便一点&#xff0c;而且也不用对wsl的子系统进行迁移。 一、安装前准备 1. 设置-Windows更新-window…

JDK1.8 安装教程(linux)

一、 检查当前系统是否已安装JDK 通过命令java –version 如果有出现如下图提示表示有安装&#xff0c;则无需再安装 二、 安装JDK 通过JDK官网https://www.oracle.com/上下载需要的JDK 版本&#xff0c;下载完成后上传到linux 系统上指定的文件夹下。&#xff08;可以用宝…

copy is all you need前向绘图 和疑惑标记

疑惑的起因 简化前向图 GPT4解释 这段代码实现了一个神经网络模型&#xff0c;包含了BERT、GPT-2和MLP等模块。主要功能是给定一个文本序列和一个查询序列&#xff0c;预测查询序列中的起始和结束位置&#xff0c;使其对应文本序列中的一个短语。具体实现细节如下&#xff1a…