【高效管理集合】并查集的实现与应用

news2024/11/18 20:34:50

在这里插入图片描述

文章目录

  • 并查集的概念
    • 主要操作
    • 优化技术
    • 应用场景
  • 并查集的实现
    • 基本框架
    • 并查集的主要接口
    • 总体代码
  • 并查集的应用
    • 省份的数量
    • 等式方程的可满足性
  • 总结

并查集的概念

并查集,也称为不相交集,是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题。简单来说,它主要用于处理元素分组的问题。

主要操作

  1. 查找(Find)
    确定元素所属的集合,通常返回该元素的根节点。

  2. 合并(Union)
    将两个集合合并为一个集合。

优化技术

  • 路径压缩
    在查找操作中,将访问路径上的节点直接连接到根节点,以减少树的高度。

  • 按秩合并
    总是将较小的树合并到较大的树下,以保持树的平衡。

应用场景

并查集广泛用于以下问题:

  • 判断两个元素是否在同一集合中。
  • 合并两个集合。
  • 最小生成树算法。
  • 网络连接问题等。

这种数据结构在许多算法中都非常有效,尤其是在处理集合合并和查询时。

并查集的实现

基本框架

class UnionFindset
{
public:
	UnionFindset(size_t n)
	{}
	//合并接口
	void Union(int x1, int x2)
	{
	}
	//找根的位置
	int FindRoot(int x)
	{
	}
	//是否在相同一个集合
	bool IsInSet(int x1, int x2)
	{
	}
	//并查集中有多少个集合
	size_t SetSize()
	{
	}
	//压缩路径
	void findWithPathCompression()
	{
	}
private:
	//下标---->人
	vector<int> _ufs;
};

在这里插入图片描述

并查集的主要接口

构造函数:
在这里插入图片描述

UnionFindset(size_t n)
	//将每个位置初始化为-1
	:_ufs(n, -1)
{}

将每个位置初始化为-1,在并查集中存储的大于零的数表示的是父亲的下标,存储的小于0的值表示的是根节点。
索引根的位置:

//找根的位置
int FindRoot(int x)
{
	int parent = x;
	//索引根的位置
	while (_ufs[parent] > 0) parent = _ufs[parent];
	return parent;
}

当下标对应的数是负数的时候,当前位置就是根。
合并不相关集合:

//合并接口
void Union(int x1, int x2)
{
	int parent1 = FindRoot(x1), parent2 = FindRoot(x2);
	//本身就在一个集合就不需要进行合并
	if (parent1 == parent2) return;
	if (parent1 > parent2) swap(parent1, parent2);
	else
	{
		_ufs[parent1] += _ufs[parent2];
		//索引下标
		_ufs[parent2] = parent1;
	}
}

合并两个不相关集合,只需要先找到根,复用上面的接口,然后将这两个集合的根进行合并即可,将任意一个根对应的数加到另一个数的根上,然后将这个跟的下标改为另一个根的下标即可,就完成了合并了。
判断是否在同一集合:
只需要判断两个节点的根是否相同即可。

//是否在相同一个集合
bool IsInSet(int x1, int x2)
{
	return FindRoot(x1) == FindRoot(x2);
}

查看有多少个集合:
只需要查看数组中有多少个小于0的位置即可。

//并查集中有多少个集合
size_t SetSize()
{
	size_t size = 0;
	for (size_t i = 0;i < _ufs.size();i++)
		if (_ufs[i] < 0)size++;
	return size;
}

压缩路径:

int FindWithPathCompression(int x)
{
    if (_ufs[x] < 0)
    {
        return x; // 找到根节点
    }
    // 递归查找根节点,并进行路径压缩
    _ufs[x] = FindWithPathCompression(_ufs[x]);
    return _ufs[x]; // 返回根节点
}

总体代码

class UnionFindset
{
public:
	UnionFindset(size_t n)
		//将每个位置初始化为-1
		:_ufs(n, -1)
	{}
	//合并接口
	void Union(int x1, int x2)
	{
		int parent1 = FindRoot(x1), parent2 = FindRoot(x2);
		//本身就在一个集合就不需要进行合并
		if (parent1 == parent2) return;
		if (parent1 > parent2) swap(parent1, parent2);
		else
		{
			_ufs[parent1] += _ufs[parent2];
			//索引下标
			_ufs[parent2] = parent1;
		}
	}
	//找根的位置
	int FindRoot(int x)
	{
		int parent = x;
		//索引根的位置
		while (_ufs[parent] > 0) parent = _ufs[parent];
		return parent;
	}
	//是否在相同一个集合
	bool IsInSet(int x1, int x2)
	{
		return FindRoot(x1) == FindRoot(x2);
	}
	//并查集中有多少个集合
	size_t SetSize()
	{
		size_t size = 0;
		for (size_t i = 0;i < _ufs.size();i++)
			if (_ufs[i] < 0)size++;
		return size;
	}
	//压缩路径
	int FindWithPathCompression(int x)
	{
	    if (_ufs[x] < 0)
	    {
	        return x; // 找到根节点
	    }
	    // 递归查找根节点,并进行路径压缩
	    _ufs[x] = FindWithPathCompression(_ufs[x]);
	    return _ufs[x]; // 返回根节点
	}
private:
	//下标---->人
	vector<int> _ufs;
};

并查集的应用

省份的数量

题目信息:

在这里插入图片描述

示例:

在这里插入图片描述

代码展示:

class Solution 
{
public:
    //给的是城市的下标
    int findCircleNum(vector<vector<int>>& isConnected) 
    {
        //vector模拟并查集行为
        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),root2=FindRoot(j);
                    if(root1!=root2)
                    {
                        //将两个合并
                        ufs[root1]+=ufs[root2];
                        //存父亲的下标
                        ufs[root2]=root1;
                    }
                }
            }
        }
        int n=0;
        for(auto e:ufs)
            if(e<0)n++;
        return n;
    }
};

等式方程的可满足性

题目信息:

在这里插入图片描述

示例:

在这里插入图片描述

代码展示:

class Solution 
{
public:
    bool equationsPossible(vector<string>& equations) 
    {
        //开26个空间
        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'),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'),root2=FindRoot(str[3]-'a');
                if(root1==root2) return false;
            }
        }
        return true;
    }
};

总结

并查集(Union-Find)是一种高效的数据结构,广泛应用于解决动态连通性问题。通过支持合并和查找操作,并查集能够有效管理和查询集合关系。其核心优化技术——路径压缩和按秩合并,显著提高了操作的效率,使得在大规模数据处理时依然保持良好的性能。

在实际应用中,理解并掌握并查集的原理和实现方式,能够帮助开发者解决许多复杂问题,如图论算法、网络连接等。通过本次介绍,希望能对并查集的概念和应用提供一个清晰的认识,为进一步的学习和实践打下基础。

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

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

相关文章

ClickHouse | 查询

1 ALL 子句 2 ARRAY JOIN 使用别名 :在使用时可以为数组指定别名&#xff0c;数组元素可以通过此别名访问&#xff0c;但数组本身则通过原始名称访问 3 DISTINCT子句 DISTINCT不支持当包含有数组的列 4 FROM子句 FROM 子句指定从以下数据源中读取数据: 1.表 2.子…

建筑资质应该怎么选?

建筑资质是建筑企业承接工程项目的必备条件&#xff0c;它不仅关系到企业的市场竞争力&#xff0c;还直接影响到企业的经营效益。因此&#xff0c;选择适合自己企业的建筑资质至关重要。以下是一些选择建筑资质时需要考虑的关键因素&#xff1a; 1. 明确企业定位 首先&#x…

金融教育宣传月 | 平安养老险百色中心支公司开展金融知识“消保县域行”宣传活动

9月22日&#xff0c;平安养老险百色中心支公司积极落实国家金融监督管理总局关于开展金融教育宣传月活动的相关要求&#xff0c;联合平安人寿百色中心支公司共同组成了平安志愿者小队&#xff0c;走进百色市四塘镇百兰村开展了一场别开生面的金融消费者权益保护宣传活动。此次活…

如何给你的项目添加测试覆盖率徽章

看完我的测试教程之后&#xff0c;想必大家都能写出一个测试覆盖率极高的小项目了。测试覆盖率既然这么高&#xff0c;不秀一秀岂不是白瞎了&#xff0c;下面我们就来通过第三方服务来给你的项目加上测试覆盖率徽章&#xff0c;涉及到的内容有yaml配置&#xff0c;githubAction…

Vue下载pubsub-js中错误问题解决

错误&#xff1a; 解决方法&#xff1a; 执行&#xff1a; npm config set registry https://registry.npm.taobao.org我执行以上方法后安装成功

关于北斗卫星导航系统,你都了解多少?

北斗卫星导航系统&#xff08;简称“北斗系统”&#xff09;&#xff0c; 英文全称是&#xff1a;Beidou Navigation Satellite System&#xff08;简称&#xff1a;BDS&#xff09;&#xff0c; 研发 的 初衷 是中国着眼于国家安全和经济社会发展需要&#xff0c;选择自主研发…

Java类的生命周期-初始化阶段

Java类的生命周期-初始化阶段 前两篇讲述了类生命周期的加载阶段和连接阶段&#xff0c;那么本篇我们来讲最为重要的初始化阶段&#xff0c;借助字节码文件与大厂面试题更好的理解类的初始化 头篇提到&#xff0c;类的生命周期可疑将他分为五个阶段&#xff0c;本篇要讲述的就是…

RIP路由(已被淘汰)

一、rip 路由原理 RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;早期的动态路由协议&#xff0c;被广泛应用于TCP/IP网络中&#xff0c;尤其是在中小型网络中。基于距离矢量&#xff08;Distance-Vector&#xff09;算法来计算到达目的网络…

农场小程序带你走进生态农产品的世界

在快节奏的现代生活中&#xff0c;人们对食品安全的关注日益增强&#xff0c;对环境、健康农产品的需求也愈发迫切。然而&#xff0c;传统农产品市场往往信息不透明&#xff0c;消费者难以直接了解农产品的生长环境和生产过程&#xff0c;导致信任缺失。而农场小程序的出现&…

工程安全监测分析模型与智能算法模型方案

工程安全监测分析模型与智能算法模型 构建大坝安全监测智能分析模型&#xff0c;以大坝立体智能感知体系为依托&#xff0c;获取大坝变形、渗流渗压、环境变量等实时监测数据&#xff0c;作为模型输入&#xff0c;实现监测数据自动预处理、特征提取、误差分析、变化趋势分析等…

大模型增量训练--基于transformer制作一个大模型聊天机器人

针对夸夸闲聊数据集&#xff0c;利用UniLM模型进行模型训练及测试&#xff0c;更深入地了解预训练语言模型的使用方法&#xff0c;完成一个生成式闲聊机器人任务。 项目主要结构如下&#xff1a; data 存放数据的文件夹 dirty_word.txt 敏感词数据douban_kuakua_qa.txt 原始语…

Qt——如何创建一个项目

前言 本文主要通过实操带领大家来实现基础文件的操作&#xff0c;主要包括文件的打开&#xff0c;读取&#xff0c;写入&#xff0c;当然文件读写我们可以有几种不同的方式来进行操作&#xff0c;分别是文件流&#xff0c;字节流来进行的操作这里就需要两个类分别是文件流&…

迈威通信闪耀工博会,以创新科技赋能工业自动化

昨日&#xff0c;在圆满落幕的第24届中国国际工业博览会上&#xff0c;迈威通信作为工业自动化与智慧化领域的先行者&#xff0c;以“创新打造新质通信&#xff0c;赋能工业数字化”为主题精彩亮相&#xff0c;向全球业界展示了我们在工业自动化领域的最新成果与创新技术。此次…

elementUI表格中某个字段(state)使用计算属性进行转换为对应中文显示

代码案例&#xff1a; <template><el-table:data"tableData"style"width: 100%"><el-table-columnprop"date"label"日期"width"180"/><el-table-columnprop"name"label"姓名"wid…

count(1),count(*)与 count(‘列名‘) 的区别

文章目录 COUNT(expr)性能对比count(*) VS count(1)count(*) VS count(列名) count(*)会走索引吗MyISAM count优化InnoDB如何处理count(*)总结 参考官方文档&#xff1a; https://dev.mysql.com/doc/refman/8.4/en/aggregate-functions.html#function_count COUNT(expr) coun…

叶国富“推翻”马云新零售,零售新王此刻登基?

63亿入主永辉超市&#xff0c;拿到29.4%股份&#xff0c;坐上永辉超市第一大股东的宝座&#xff0c;名创优品创始人叶国富&#xff0c;成为了新科“零售之王”。 很是霸气外漏。 有投资者表示费解&#xff0c;不明白为何此时入局超市行业&#xff0c;叶国富当即召开电话会议&…

数据结构:树的定义及其性质

树的定义 树是一种重要的非线性数据结构&#xff0c;树作为一种逻辑结构&#xff0c;同时也是一种分层结构。具有以下两个特点&#xff1a; 1.树的根结点没有前驱&#xff0c;除根结点意外的节点只有一个前驱 2.树中所有结点都可以有0个或多个后继 树结构在多个领域都有广泛…

JVM相关的命令汇总

一、简介 虽然目前市场上有很多成熟的 JVM 可视化监控分析工具&#xff0c;但是所有的工具其实都依赖于 JDK 的接口和底层相关的命令&#xff0c;了解这些命令的使用对于在紧急情况下排查 JVM 相关的线上故障&#xff0c;会有更加直观的帮助。 下面一起来看看 JVM 常用的命令…

ARM硬件知识补充

一、硬件知识 1.三极管 三极管定义&#xff1a;全称应为半导体三极管&#xff0c;也被称为双极型晶体管或晶体三极管。 主要功能&#xff1a;是将微弱的电信号放大成幅度值较大的电信号&#xff0c;同时也被用作无触点开关。 分类&#xff1a;分为NPN型和PNP型两种类型。 …

GNSS定位中自适应调整电离层延迟参数过程噪声的方法

文章目录 前言一、非差非组合PPP模型二、电离层功率谱密度计算三、具体实现方法3.1 不平滑3.2 三阶多项式平滑 参考文献 前言 GNSS定位中不少技术手段如PPP和长基线RTK需要将电离层延迟作为参数估计&#xff0c;电离层延迟的变化通常被描述为随机游走过程&#xff0c;而功率谱密…