C++数据结构:并查集

目录

一. 并查集的概念

二. 并查集的模拟实现

2.1 并查集类的声明

2.2 并查集的实现

三. 路径压缩

四. 总结


一. 并查集的概念

在生活中,我们经常需要对某一些事物进行归类处理,即:将N个不同的元素划分为几个互不相交的集合。在初始状态,每个元素都属于一个独立的集合,在归一合并的过程中,经常需要查找某个元素属于哪一个集合,实现上面功能的数据结构,称之为并查集。

举一个生活中的例子,假设小卖部了有如下货物:苹果、香蕉、橘子、面包、薯片、牙膏、毛巾等,一开始进货的时候,这些货物是散装进货的,没有归类。一般而言,我们会将苹果、香蕉、橘子归类为水果,将面包和薯片归为零食,将牙膏和毛巾归为洗漱用品,这就相当于并查集查找元素所属的几何并进行归类的过程。初步归类后,继续将水果和零食统一归类为食物,这相当于合并两个类,并查集可以实现对类的合并。

并查集本质上是通过多颗树(森林)来实现的,每一颗树都表示一个独立的集合,使用双亲法表示树结构,即每个节点仅保存其父亲节点。如图1.1所示,将1~9十个数字分为三个集合,分别为{0,5,6,9}、{1,4,7}、{2,3,8},用三棵树表示对应关系,取{...}中第一个数据为根节点,使用vector<int>数组来实现双亲法表示树状结构,假设数据与vector下标直接对应,那么并查集划分集合的过程为:

  • 先将vector<int>中每个元素都设为-1,表示每个元素属于独立的集合。
  • 开始进行归一化,对于每个叶子节点,查找其根节点,根节点值-1,叶子节点位置处值为其父亲节点的下标。
  • 归类完成后,根节点下标处的值为负数,叶子节点下标处的值>=0
  • 对于叶子节点下标处的负数值,设其为rootVal,有:abs(rootVal) = 本集合的数据个数。
图1.1 并查集归类

如图1.2所示,将图1.1中的{0,5,6,9}和{1,4,7}归为一类,那么1就变为了0的孩子节点,合并后的几集合以0为根节点,有7个元素,因此vector<int>下标为0的位置处元素变为了-1,而原来下标为1的位置处的值变为合并后其父亲节点的值的下标,即0。

图1.2 并查集合并集合

二. 并查集的模拟实现

2.1 并查集类的声明

我们假设并查集要管理的元素值从1~N,不考虑模板类型数据和vector<int>下标的映射情况,根据第一节的内容,一个并查集类应当以下成员变量和接口:

  • std::vector<int> _ufs :用于以双亲表示法记录每一颗树(每一个集合)。
  • 构造函数 :给定数据量,将_ufs中的元素全部初始化为-1。
  • int FindRoot(int x),查找元素x所属的根在_ufs中的下标。
  • void Union(int x1, int x2) :将x1和x2所在的集合合并为一个集合。
  • size_t Size() :统计并查集内集合的个数。
  • 析构函数 :采用编译器默认生成的析构函数即可。

代码2.1:并查集类UnionFindSet的声明(UnionFindSet.hpp头文件)

#pragma once
#include <iostream>
#include <vector>
#include <algorithm>// 并查集
class UnionFindSet
{
public:UnionFindSet(size_t size);int FindRoot(int x);         // 查找某个元素属于哪个集合(根下标)void Union(int x1, int x2);  // 合并两个集合size_t Size() const;         // 统计并查集内集合的个数private:std::vector<int> _ufs;
};

2.2 并查集的实现

  • 构造函数:给定数据量size,将_ufs初始化为函数size个值为-1的线性表,表示每个元素都属于一个独立的集合。
  • 根查找函数int FindRoot(int x):本质上为查找元素属于哪一个集合,前面提到根下标处的元素为负数,因此只需要不断更新x = _ufs[x],直到_ufs[x] < x,然后将x返回即可。
  • 集合合并函数void Union(int x1, int x2):先查找两个元素的根root1和root2,如果root1 == root2成立,则表明两个元素属于同一集合,这种情况下直接返回即可。如果root1 != root2,那么就让_ufs[root1] += _ufs[root2],这样根节点下标位置处的绝对值就是集合中元素的个数,然后再执行_ufs[root2] = _ufs[root1],表示跟新被合并集合的根节点。
  • 统计集合个数函数size_t Size():统计根节点个数,即_ufs中小于0的元素的个数即可。

代码2.2:并查集的实现(UnionFindSet.cpp源文件)

#define _CRT_SECURE_NO_WARNINGS 1#include "UnionFindSet.hpp"UnionFindSet::UnionFindSet(size_t size): _ufs(size, -1)
{ }// 查找某个元素属于哪个集合(根下标)
int UnionFindSet::FindRoot(int x)
{// 循环查找,直到_ufs[x] < 0while (_ufs[x] >= 0){x = _ufs[x];}return x;
}// 合并两个集合
void UnionFindSet::Union(int x1, int x2)
{int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2){return;}if (root1 > root2){std::swap(root1, root2);}_ufs[root1] += _ufs[root2];_ufs[root2] = root1;
}// 统计并查集内集合的个数
size_t UnionFindSet::Size() const
{// 遍历_ufs统计小于0的元素的个数size_t count = 0;for (const auto x : _ufs){if (x < 0) ++count;}return count;
}

三. 路径压缩

如果并查集中毒元素数量过多,那么每次查找根节点都需要花费较大的成本,那么,就需要采取适当的手段来进行路径压缩。

路径压缩最常用的方法:每当查找完一个元素所属集合的根节点后,都将这个元素的父亲节点直接设备根节点,这样当第二次查找这个元素的根节点时,就只需要向上查找一层即可。

如图3.1所示,假设要查找5的根节点,并进行路径压缩,只需要在找到5的根节点0后,将5挂在0的下面即可。当然,如果元素的数量不是很大,就没必要考虑路径压缩,因为路径压缩本身也存在资源消耗

图3.1 路径压缩

四. 总结

  • 并查集,是通过双签法实现多颗树(森林),来进行数据分类的数据结构。
  • 并查集能够实现的功能包括:查找元素所属集合(根节点)、合并集合、统计集合数目。
  • 如果并查集中元素的数目过多,那么应当进行路径压缩。

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

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

相关文章

镭速,克服UDP传输缺点的百倍提速传输软件工具

在网络传输中&#xff0c;我们经常会面临这样的困难&#xff1a;文件太大&#xff0c;传输速度太慢&#xff0c;浪费时间和流量&#xff1b;文件太小&#xff0c;传输速度太快&#xff0c;容易出现丢包和乱序&#xff0c;损害数据的完整性和正确性。这些困难的根本在于传输层协…

单图像3D重建AI算法综述【2023】

计算机视觉是人工智能的一个快速发展的领域&#xff0c;特别是在 3D 领域。 本概述将考虑一个应用任务&#xff1a;2D 和 3D 环境之间的转换。 在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编…

小红书为什么没人看,小红书爆款标题怎么写?

作为快节奏的社会&#xff0c;人们追求的是不仅仅是高价值更是高性价比&#xff0c;和吸引度。而标题类似于门面&#xff0c;吸引程度自然作为重中之重。今天我们和大家分享下小红书为什么没人看&#xff0c;小红书爆款标题怎么写&#xff1f; 以母婴类型为例子&#xff0c;母婴…

《云计算:云端协同,智慧互联》

《云计算&#xff1a;云端协同&#xff0c;智慧互联》 云计算&#xff0c;这个科技领域中的热门词汇&#xff0c;正在逐渐改变我们的生活方式。它像一座座无形的桥梁&#xff0c;将世界各地的设备、数据、应用紧密连接在一起&#xff0c;实现了云端协同&#xff0c;智慧互联的愿…

网络参考模型与标准协议(二)-TCP/IP对等模型详细介绍

应用层 应用层为应用软件提供接口&#xff0c;使应用程序能够使用网络服务。应用层协议会指定使用相应的传输层协议&#xff0c;以及传输层所使用的端口等。TCP/IP每一层都让数据得以通过网络进行传输&#xff0c;这些层之间使用PDU ( Paket Data Unit,协议数据单元)彼此交换信…

Ubuntu(Linux)的基本操作

基本操作三步走 1、输入vim code.c点击i&#xff08;出现insert&#xff09;表示可以编辑代码编辑代码之后按下esc&#xff08;退出编辑模式&#xff09;按下shift:&#xff08;冒号&#xff09;wq&#xff08;退出文件&#xff09;2、输入gcc code.c&#xff08;进行编译代码…

【知识增强】A Survey of Knowledge-Enhanced Pre-trained LM 论文笔记

A Survey of Knowledge-Enhanced Pre-trained Language Models Linmei Hu, Zeyi Liu, Ziwang Zhao, Lei Hou, Liqiang Nie, Senior Member, IEEE and Juanzi Li 2023年8月的一篇关于知识增强预训练模型的文献综述 论文思维导图 思维导图网页上看不清的话&#xff0c;可以存…

软件测试:测试分类

一. 按照测试对象划分 1.1 界面测试 界面测试(简称UI测试),按照界面的需求(UI设计稿)和界面的设计规则,对我们软件界面所展示的全部内容进行测试和检查,一般包括如下内容: • 验证界面内容的完整性,一致性,准确性,友好性,兼容性.比如页面内容对屏幕大小的自适应,换行,内容是否…

Leetcode—206.反转链表【简单】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—206.反转链表 头插法实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* reverseList(struct ListNode* head) {if(head NULL…

ajax,axios,fetch

文章目录 ajax工作原理ajax发请求四个步骤创建xmlhttprequest对象设置请求方式设置回调函数发送请求 自封装ajax axiosaxios 特性如何用配置拦截器fetch 三者区别 ajax 工作原理 Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎)&#xff0c;使用户操作与服务…

HDD与QLC SSD深度对比:功耗与存储密度的终极较量

在当今数据世界中&#xff0c;存储设备的选择对于整体系统性能和能耗有着至关重要的影响。硬盘HDD和大容量QLC SSD是两种主流的存储设备&#xff0c;而它们在功耗方面的表现是许多用户关注的焦点。 扩展阅读&#xff1a; 1.面对SSD的步步紧逼&#xff0c;HDD依然奋斗不息 2.…

Windows系统中搭建docker (ubuntu,Docker-desktop)

一、docker安装前的准备工作 1. 开启CPU虚拟化&#xff0c;新电脑该默认是开启的&#xff0c;如果没开启可以根据自己电脑型号品牌搜索如克开启CPU虚拟化。当开启成功后可在设备管理器中看到。 2.开通Hyper-V 通过 Windows 控制面板 --> 程序和功能 -->启用或关闭…

Java集合大总结——Set的简单使用

Set的简单介绍 Set接口是Collection的子接口&#xff0c;Set接口相较于Collection接口没有提供额外的方法。Set 集合不允许包含相同的元素&#xff0c;如果试把两个相同的元素加入同一个 Set 集合中&#xff0c;则添加操作失败。Set集合支持的遍历方式和Collection集合一样&am…

[Kettle] 生成记录

在数据统计中&#xff0c;往往要生成固定行数和列数的记录&#xff0c;用于存放统计总数 需求&#xff1a;为方便记录1~12月份商品的销售总额&#xff0c;需要通过生成记录&#xff0c;生成一个月销售总额的数据表&#xff0c;包括商品名称和销售总额两个字段&#xff0c;记录…

使用键盘管理器更改键盘快捷键,让键盘真正迎合你的使用习惯

如果默认快捷键不适合你&#xff0c;你肯定会想知道如何在Windows 11中更改键盘快捷键。 也许你已经习惯了macOS键盘&#xff0c;或者像我一样在Windows和Mac之间切换工作/游戏——如果是这样的话&#xff0c;重新配置默认的Windows快捷方式&#xff0c;使其与Mac上的快捷方式…

Docker网络详细说明

Docker网络 docker不启动&#xff0c;默认网络情况 ipconfig----------ens33、lo、virbr0 在CentOS7的安装过程中如果有选择相关虚拟化的的服务安装系统后&#xff0c;启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡&#xff1a;它还有一个固定的默认I…

多目标应用:基于多目标灰狼优化算法MOGWO求解微电网多目标优化调度(MATLAB代码)

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、多目标灰狼优化算法MOGWO 多目标灰狼优化算法MOGWO简介&#xff1a; 三、多目标灰狼优化算法MOGWO求解微电网多目标优化调度 &#xff08;1&#xff09…

ANSYS网格无关性检查

网格精度对应力结果存在很大的影响&#xff0c;有时候可以发现&#xff0c;随着网格精度逐渐提高&#xff0c;所求得的最大应力值逐渐趋于收敛。 默认网格&#xff1a; 从默认网格下计算出的应力云图可以发现&#xff0c;出现了的三处应力奇异点&#xff0c;此时算出的应力值是…

趣学python编程(六、关于蓝桥杯比赛)

蓝桥杯全国软件和信息技术专业人才大赛简称“蓝桥杯”&#xff0c;是由工业和信息化部人才交流中心举办的国内最大的信息技术竞赛。为促进中小学科技创新&#xff0c;提升中小学生逻辑思维&#xff0c;发现和培养面向未来的科技精英人才。 蓝桥杯介绍 蓝桥杯全国软件和信息技术…

Linux操作系统使用及C高级编程-D6-D8Linux shell脚本

利用shell命令写的脚本文件&#xff0c;后缀是.sh shell脚本是一个解释型语言&#xff0c;不需要编译&#xff0c;可直接执行 书写&#xff1a;vi test.sh #!/bin/bash&#xff1a;说明使用的是/bin目录下的bash 说明完后即可编写脚本文件 bash test.sh&#xff1a;运行文…