【高阶数据结构】秘法(一)——并查集:探索如何高效地管理集合

news2024/9/21 6:04:06

前言:

前面我们已经学习了简单的数据结构,包括栈与队列、二叉树、红黑树等等,今天我们继续数据结构的学习,但是难度上会逐渐增大,在高阶数据结构中我们要学习的重点是图等

目录

一、并查集的原理

二、并查集的基本操作

三、并查集的实现(简略版)

四、并查集的实现方式和优化策略

五、并查集的实现(完整版)

六、总结


一、并查集的原理

在某些情况下,对于一组元素,我们会把它们划分成不同的集合。起初每个元素组成一个单元素集合,然后按照一定规律将归于同一种类型的集合合并,同时在这个过程中我们可能会反复用到查询某个元素属于哪个集合的运算,这种管理集合所对应的抽象概念就是并查集


并查集,也称为链接-切割数据结构,是一种用于管理集合的高效数据结构。它特别适用于处理“动态连接”的问题,即动态地合并集合或查询两个元素是否属于同一个集合。并查集在计算机科学中有着广泛的应用,如用于解决最小生成树问题(Prim算法和Kruskal算法)、解决网络连通性问题、解决图论中的问题等。


下面来看这样一个例子:某旅游团内有游客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}就相互认识了,10个人形成了三个小团体。假设右三个群主0,1,2担任队长,负责大家的出行。
一趟火车之旅后,每个小分队成员就互相熟悉,称为了一个朋友圈。
从上图可以看出:编号6,7,8游客属于0号小分队,该小分队中有4人(包含队长0);编号为4和9的同学属于1号小分队,该小分队有3人(包含队长1),编号为3和5的游客属于2号小分队,该小分队有3个人(包含队长1)。
仔细观察数组中内融化,可以得出以下结论:
1. 数组的下标对应集合中元素的编号
2. 数组中如果为负数,负号代表根,数字代表该集合中元素个数
3. 数组中如果为非负数,代表该元素双亲在数组中的下标

回家一段时间后,西安小分队中8号游客与成都小分队1号游客奇迹般的走到了一起,两个小圈子的游客相互介绍,最后成为了一个小圈子:
现在0集合有7个人,2集合有3个人,总共两个朋友圈
通过以上例子可知,并查集一般可以解决一下问题:
1. 查找元素属于哪个集合
沿着数组表示树形关系以上一直找到根(即:树中中元素为负数的位置)
2. 查看两个元素是否属于同一个集合
沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在
3. 将两个集合归并成一个集合
将两个集合中的元素合并
将一个集合名称改成另一个集合的名称
4. 集合的个数 
遍历数组,数组中元素为负数的个数即为集合的个数。

二、并查集的基本操作

并查集主要支持以下三种基本操作:

  1. 查找(Find):确定一个元素属于哪个集合。
  2. 合并(Union):将两个集合合并为一个集合。
  3. 初始化(Init):为每个元素创建一个独立的集合。

三、并查集的实现(简略版)

根据上面讲的原理和预期功能,我们可以先来实现一个简略版的并查集:
class UnionFindSet
{
public:
	// 初始时,将数组中元素全部设置为-1
	UnionFindSet(size_t size)
		: _ufs(size, -1)
	{}
	// 给一个元素的编号,找到该元素所在集合的名称
	int FindRoot(int index)
	{
			// 如果数组中存储的是负数,找到,否则一直继续
			while (_ufs[index] >= 0)
			{
				index = _ufs[index];
			}

		return index;
	}
	bool Union(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);

		// x1已经与x2在同一个集合
		if (root1 == root2)
			return false;

		// 将两个集合中元素合并
		_ufs[root1] += _ufs[root2];

		// 将其中一个集合名称改变成另外一个
		_ufs[root2] = root1;
		return true;
	}
	// 数组中负数的个数,即为集合的个数
	size_t Count()const
	{
		size_t count = 0;
		for (auto e : _ufs)
		{
			if (e < 0)
				++count;
		}

		return count;
	}

private:
	vector<int> _ufs;
};

四、并查集的实现方式和优化策略

并查集有两种常见的实现方式:路径压缩和按秩合并。

  • 路径压缩:在查找操作中,将查找路径上的所有节点的父节点直接指向根节点,以减少查找路径的深度。
  • 按秩合并:在合并操作中,将秩较小的集合合并到秩较大的集合中,以减少树的高度。

为了提高查找操作的效率,通常结合使用路径压缩和按秩合并两种策略。路径压缩确保查找操作的时间复杂度接近常数,而按秩合并则减少了树的高度,进一步优化了合并操作的时间复杂度。

五、并查集的实现(完整版)

#include <iostream>
#include <vector>

class UnionFind {
private:
    std::vector<int> parent;
    std::vector<int> rank;

public:
    UnionFind(int n) : parent(n), rank(n) {
        for (int i = 0; i < n; ++i) {
            parent[i] = i;
            rank[i] = 1;
        }
    }

    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]); // 路径压缩
        }
        return parent[x];
    }

    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX == rootY) return;

        if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else {
            parent[rootY] = rootX;
            rank[rootX] += 1;
        }
    }

    bool connected(int x, int y) {
        return find(x) == find(y);
    }
};

int main() {
    int n, m;
    std::cin >> n >> m;
    UnionFind uf(n);
    for (int i = 0; i < m; ++i) {
        int a, b;
        std::cin >> a >> b;
        uf.unite(a - 1, b - 1); // 转换为0-based索引
    }
    for (int i = 0; i < m; ++i) {
        int a, b;
        std::cin >> a >> b;
        std::cout << (uf.connected(a - 1, b - 1) ? "YES" : "NO") << std::endl;
    }
    return 0;
}

六、总结

并查集的高效性在于其优化策略,使得查找和合并操作的时间复杂度保持在较低的水平,从而在处理大规模数据集时依然表现出色。平时我们在刷题或学习中还是会经常遇到并查集的

感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

嘉兴银行业绩上涨却市值下滑,新任行长背后的辛酸

撰稿|芋圆 2024年3月6日&#xff0c;秦山核电有限公司&#xff08;以下简称“泰山核电”&#xff09;在上海联合产权交易所转让其所持有的嘉兴银行股份有限公司&#xff08;下称“嘉兴银行”&#xff09;的全部股份630万股的&#xff0c;占嘉兴银行总股本的0.3272%&#xff0c…

【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C 目录 前言 一、类的概念及定义 1. 类的定义格式 2. 访问限定符 二、类域 三、类的实例化--对象 1. 实例化的概念 2. 对象的内存大小 四、this指针 …

Vue——认识day02

此处接上一篇文章Vue——初识Vue开始&#xff0c;欢迎大家。 目录 1.MVVM模型 2.Object.defineproperty方法 3.数据代理简介 4.Vue中的数据代理 总结 1.MVVM模型 MVVM模型是一种软件架构模式&#xff0c;用于将用户界面&#xff08;View&#xff09;&#xff0c;业务逻辑&…

牛客周赛 Round 35 (A~G)

本次A~D较为简单&#xff0c;E是一道很好的构造题&#xff0c;FG主要就是考察组合数和约数个数 A.小红的字符串切割 思路 &#xff1a;签到题 void solve() {string s;cin>>s;int lens.size();cout<<s.substr(0,len/2)<<endl<<s.substr(len/2); }B.小…

搭建面向切面编程项目

此项目在整合Mybatis基础上修改&#xff0c;可参考主页的整合Mybatis文章 注解版本 第一步 引入maven坐标 <!-- 切面编程所需jar包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>…

Chapter 04 Vue指令(下)

欢迎大家订阅【Vue2Vue3】入门到实践 专栏&#xff0c;开启你的 Vue 学习之旅&#xff01; 文章目录 前言一、指令修饰符二、v-bind对于样式操作的增强三、v-model应用于表单元素 前言 在 Vue.js 中&#xff0c;指令是带有 v- 前缀的特殊属性&#xff0c;不同属性对应不同的功…

[原理理解] Swin Transformer相对位置编码理解

文章目录 简述相对位置编码的意义直观理解注意力相对位置获取必要性当前位置初步获取利用广播机制获取相对位置索引XY获取最后相对位置1获取最后相对位置2最终的相对位置值嵌入 简述 在看Swin Transformer的时候&#xff0c;一开始在相对位置编码这一块的理解上卡壳了挺久&…

27 Combobox组件

Tkinter ttk.Combobox 组件使用指南 ttk.Combobox 是 Tkinter 的一个高级控件&#xff0c;它结合了文本框和下拉列表的功能&#xff0c;允许用户从预定义的选项列表中选择一个值。ttk 模块是 Tkinter 的一个扩展&#xff0c;提供了更现代的控件外观和行为。以下是对 ttk.Combo…

hyperf json-rpc

安装 安装docker hyperf 安装 hyperf-rpc-server-v8 &#xff08;服务端&#xff09; docker run --name hyperf-rpc-server-v8 \ -v /www/docker/hyperf-rpc-server:/data/project \ -w /data/project \ -p 9508:9501 -it \ --privileged -u root \ --entrypoint /bin/sh \…

港口行业大数据BI建设方案(24页PPT)

方案简介&#xff1a; 港口行业BI建设方案旨在通过数据整合、分析、可视化及智能化决策支持等手段&#xff0c;提升港口运营效率与管理水平。它的建设实施有利推动港口数字化转型、是提升竞争力的关键举措。通过构建高效、智能的BI系统&#xff0c;港口企业能够实现对运营数据…

软设例题—哈夫曼树

哈夫曼树基本概念&#xff1a; 叶子结点的路径长度&#xff1a;结点到根的分支数量 树的路径长度&#xff1a;所有叶子结点路径长度之和 权&#xff1a;叶子结点的数值 叶子结点的带权路径长度&#xff1a;权重*路径 树的带权路径长度&#xff1a;所有叶子结点带权路径之和…

# Windows 系统安装 virtualbox/vmware 虚拟机教程

Windows 系统安装 virtualbox/vmware虚拟机教程 段子手-168 2024-8-28 一、virtualbox/vmware 简介 1、VirtualBox VirtualBox 是开源的、免费虚拟机软件。VirtualBox 是由德国 Innotek 公司开发&#xff0c;由 Sun Microsystems 公司出品的软件&#xff0c;号称是最强的免…

前端学习笔记-Web APIs篇-01

变量声明 变量声明有三个 var let 和 const 建议&#xff1a; const 优先&#xff0c;尽量使用const&#xff0c; 原因是&#xff1a; const 语义化更好很多变量我们声明的时候就知道他不会被更改了&#xff0c;那为什么不用 const呢&#xff1f;实际开发中也是&#xff0c…

如何使用ssm实现基于ssm的软考系统+vue

TOC ssm321基于ssm的软考系统vue 系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#x…

11 索引

目录 没有索引&#xff0c;可能会有什么问题认识磁盘 1. 没有索引&#xff0c;可能会有什么问题 所以&#xff1a;提高数据库的性能&#xff0c;索引是物美价廉的东西。不用加内存&#xff0c;不用改程序&#xff0c;不用调sql&#xff0c;只要执行正确的create index&#x…

Python 数据分析笔记— Numpy 基本操作

文章目录 学习内容&#xff1a;一、什么是数组、矩阵二、创建与访问数组三、矩阵基本操作 学习内容&#xff1a; 一、什么是数组、矩阵 数组&#xff08;Array&#xff09;&#xff1a;是有序的元素序列&#xff0c;可以是一维、二维、多维。 array1 [1,2,3] 或[a, b, c, d…

Littorine生物合成糖基转移酶和酰基转移酶-文献精读39

Functional genomics analysis reveals two novel genes required for littorine biosynthesis 功能基因组学分析揭示了两个Littorine生物合成所需的新基因&#xff0c;基因组挖掘很有效果~ 摘要 一些茄科药用植物能够生产药用莨菪烷类生物碱&#xff08;TAs&#xff09;&am…

MYSQL:简述对B树和B+树的认识

MySQL的索引使用B树结构。 1、B树 在说B树之前&#xff0c;先说说B树&#xff0c;B树是一个多路平衡查找树&#xff0c;相较于普通的二叉树&#xff0c;不会发生极度不平衡的状况&#xff0c;同时也是多路的。 B树的特点是&#xff1a;他会将数据也保存在非叶子节点。而这个…

样本存储需要注意的事项

在实验室和研究机构中&#xff0c;有一些样本是非常重要且需要特殊保护的&#xff0c;这些样本可能包括珍贵的细胞培养物、生物医学样本、药物试剂等等&#xff0c;为了保证这些样本的质量和完整性&#xff0c;采取一些特殊的措施来进行存储管理非常重要。 一旦这些珍贵样本出…

Undertow 性能、配置

一、性能对比 Tomcat vs Jetty vs Undertow性能对比,详细文章: Tomcat vs Jetty vs Undertow性能对比-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1699803压测指标的结果: 吞吐量:Undertow > Jetty > Tomcat响应时间&…