C++数据结构:并查集

news2024/11/15 9:44:40

目录

一. 并查集的概念

二. 并查集的模拟实现

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] < 0
	while (_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.coloradmin.cn/o/1231573.html

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

相关文章

SpringCloud微服务通信两种方式Feign和Dubbo:Feign基本使用、自定义配置、使用优化;Dubbo基本实现

RestTemplate存在的问题 代码可读性差&#xff0c;编程体验不统一参数复杂&#xff0c;URL难以维护 Feign远程调用 Feign简介 ​ Feign是SpringCloud提供的一个声明式的伪Http客户端&#xff0c;它使得调用远程服务就像调用本地服务一样简单&#xff0c;只需要创建一个接口…

指针变量和地址

A.指针变量和地址 理解了内存和地址的关系&#xff0c;我们再回到C语⾔&#xff0c;在C语⾔中创建变量其实就是向内存申请空间&#xff0c;比如&#xff1a; #include <stdio.h> int main() {int a 10;return 0; } ⽐如&#xff0c;上述的代码就是创建了整型变量a&…

Android设计模式--责任链模式

无善无恶心之体&#xff0c;有善有恶意之动。知善知恶是良知&#xff0c;为善去恶是格物。 一&#xff0c;定义 使多个对象都有机会处理请求&#xff0c;从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直…

AcWing 717. 简单斐波那契

原题链接 题目 以下数列 0 1 1 2 3 5 8 13 21 … 被称为斐波纳契数列。 这个数列从第 3 项开始&#xff0c;每一项都等于前两项之和。 输入一个整数 N &#xff0c;请你输出这个序列的前 N 项。 输入格式 一个整数 N 。 输出格式 在一行中输出斐波那契数列的前 N 项&…

Visio免费版!Visio国产平替软件,终于被我找到啦!

作为一个职场人士&#xff0c;我经常需要绘制各种流程图和图表&#xff0c;而Visio一直是我使用的首选工具。但是&#xff0c;随着公司的发展和工作的需要&#xff0c;我逐渐发现了Visio的优点和不足。 首先&#xff0c;让我们来看看Visio的优点。Visio是一个专业的流程图和图…

生成perf flame性能分析图

flame svg图是一种用来可视化CPU的调用栈的图形&#xff0c;可以帮助分析程序的性能瓶颈。flame svg图的每一列代表一个CPU的采样点&#xff0c;每一行代表一个函数调用&#xff0c;颜色代表不同的函数或模块。flame svg图的高度表示CPU的利用率&#xff0c;宽度表示函数的执行…

PCIe协议加持,SD卡9.1规范达到媲美SSD的速度4GB/s

近日&#xff0c;SD协会&#xff08;SDA&#xff09;宣布了最新的SD Express存储卡的进化&#xff0c;将microSD Express存储卡的速度提高了一倍&#xff0c;达到2GB/s&#xff0c;并引入了4个新的SD Express速度等级&#xff0c;以确保新的SD 9.1规范中最低的顺序性能水平。这…

基于梯度算法优化概率神经网络PNN的分类预测 - 附代码

基于梯度算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于梯度算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于梯度优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

常见负载均衡算法/策略(概念)

目录 1.1. 轮循均衡&#xff08;Round Robin&#xff09; 1.2. 权重轮循均衡&#xff08;Weighted Round Robin&#xff09; 1.3. 随机均衡&#xff08;Random&#xff09; 1.4. 权重随机均衡&#xff08;Weighted Random&#xff09; 1.5. 响应速度均衡&#xff08;R…

场景交互与场景漫游-对象选取(8-2)

对象选取示例的代码如程序清单8-11所示&#xff1a; /******************************************* 对象选取示例 *************************************/ // 对象选取事件处理器 class PickHandler :public osgGA::GUIEventHandler { public:PickHandler() :_mx(0.0f), _my…

Excel数据可视化—波士顿矩阵图【四象限图】

EXCEL系列文章目录 Excel系列文章是本人亲身经历职场之后萌发的想法&#xff0c;为什么Excel覆盖如此之广&#xff0c;几乎每个公司、学校、家庭都在使用&#xff0c;但是它深藏的宝藏功能却很少被人使用&#xff0c;PQ、BI这些功能同样适用于数据分析&#xff1b;并且在一些需…

海云安入选证券期货业网络和数据安全实验室“安全合作伙伴”--助力金融科技产业安全发展

近日&#xff0c;为进一步把握数字经济发展新机遇&#xff0c;推进金融与科技深度融合&#xff0c;推动金融业高质量发展&#xff0c;搭建产业链各方交流分享平台。以“数向金科&#xff0c;智引未来”为主题的2023&#xff08;第六届&#xff09;金融科技产业大会在北京举办。…

#gStore-weekly | gAnswer的使用

gAnswer能够将自然语言问题转化成包含语义信息的查询图&#xff0c;然后&#xff0c;将查询图转化成标准的SPARQL查询&#xff0c;并将这些查询在图数据库中执行&#xff0c;最终得到用户的答案。这篇文章将介绍gAnswer的使用。 目前gAnswer仅仅提供了HTTP API&#xff0c;以J…

1688API接口接入|阿里1688-B类电商基础链路专业化体验升级

新挑战&#xff0c;新契机&#xff01; 当下整个互联网的竞争环境的变化为我们带来新的机遇和挑战。1688作为连接中小生产商、贸易商和零售商的源头货源首选平台&#xff0c;持续不断地为B类买家提供更专业的服务和更优质的源头厂货供给&#xff0c;打造核心竞争力。 面对新的…

管家婆订货易在线商城任意文件上传漏洞复现

0x01 产品简介 管家婆订货易&#xff0c;帮助传统企业构建专属的订货平台&#xff0c;PC微信APP小程序h5商城5网合一&#xff0c;无缝对接线下的管家婆ERP系统&#xff0c;让用户订货更高效。支持业务员代客下单&#xff0c;支持多级推客分销&#xff0c;以客带客&#xff0c;拓…

比赛调研资料

视觉文旅 现有的模型 数据 功能 精准营销 基于地理推荐能力 乡村圈分析能力 都市圈分析能力 产品体系 三大数据平台 携程问道 旅游服务框架&#xff1a;前置&#xff08;推荐种草&#xff09;&#xff0c;途中&#xff08;客服&#xff09;&#xff0c;售后&#xff0…

淘宝商品详情数据接口(Taobao.item_get)

淘宝商品详情接口是一种程序化的接口&#xff0c;允许开发者根据商品ID或商品链接&#xff0c;获取淘宝平台上的商品详细信息。通过这个接口&#xff0c;开发者可以方便地获取商品的标题、价格、销量、描述等数据&#xff0c;进而提供给用户进行展示和购买。 使用淘宝商品详情…

基于饥饿游戏算法优化概率神经网络PNN的分类预测 - 附代码

基于饥饿游戏算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于饥饿游戏算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于饥饿游戏优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

前端入门(二)Vue2到Vue3

文章目录 Vue简介Vue的特点Hello, Vue Vue基本语法模板语法数据绑定&#xff08;v-bind、v-model&#xff09;el与data的两种写法 数据代理实现原理Object.defineProperty()数据代理 事件处理&#xff08;v-on:click / click&#xff09;事件修饰符键盘事件&#xff08;略&…

关于RecyclerView的瀑布流 分割线左右间距问题

记录一下开发遇到的RecyclerView 的 瀑布流 左右间距设置问题。 在GridLayoutManager中 &#xff0c;item的布局顺序为 在该布局中&#xff0c;他的index就是左右左右&#xff0c;position所对应的itemView就是准确的。即 左0&#xff0c;右1&#xff0c;左2&#xff0c;右3&a…