C++ 代码实例:并查集简单创建工具

news2024/11/26 20:39:50

文章目录

  • 前言
  • 代码仓库
  • 代码
    • 说明
    • main.cpp
    • Makefile
  • 结果
  • 总结
  • 参考资料
  • 作者的话

前言

C++ 代码实例:并查集简单创建工具。


代码仓库

  • yezhening/Programming-examples: 编程实例 (github.com)
  • Programming-examples: 编程实例 (gitee.com)

代码

说明

  • 简单地创建并查集
  • 注释有详细的步骤解析
  • 还可优化的点:使用cmake;使用右值传递复杂容器减小开销

注:半个晚上完成,大概测试了下


main.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>

using std::cout;
using std::endl;
using std::pair;
using std::sort;
using std::unordered_map;
using std::vector;

// 并查集类
class DisjointSet
{
public:
    // 构造并查集
    // 参数:等价关系元素值的大小/范围,等价关系集合向量
    DisjointSet(const int &e_q_s, const vector<pair<int, int>> &e_r_v) : eq_rel_size(e_q_s), eq_rel_vec(e_r_v)
    {
        // 1. 初始化元素父节点向量,大小是等价关系元素值的大小/范围,每个元素的父节点约定为自身
        this->parent_vec.resize(this->eq_rel_size); // 元素父节点的向量的大小是等价关系元素值的大小/范围
        for (int i = 0; i < this->eq_rel_size; ++i)
        {
            parent_vec[i] = i;
        }

        // 2. 初始化元素深度向量,大小是等价关系元素值的大小/范围,每个元素作为根节点约定为0即第0层
        // 合并操作依据树的深度优化,即优先将深度大的树的根挂接到深度小的树的根
        this->depth_vec.resize(this->eq_rel_size, 0);

        // 3. 按照字典序排序等价关系集合向量
        sort(this->eq_rel_vec.begin(), this->eq_rel_vec.end());

        // 4. 合并集合
        for (const auto &eq_rel_pair : eq_rel_vec) // 对每一个等价关系集合,如:{1, 2}
        {
            // 4.1 分别查找两关系元素的根节点
            int first_root = this->find_parent(eq_rel_pair.first);
            int second_root = this->find_parent(eq_rel_pair.second);

            // 4.2 依据根节点情况合并挂接
            if (first_root == second_root) // 相等不操作
            {
                continue;
            }
            else // first_root != second_root
            {
                if (this->depth_vec[first_root] < this->depth_vec[second_root]) // 优先将深度大的树的根挂接到深度小的树的根
                {
                    this->parent_vec[first_root] = second_root;
                }
                else if (this->depth_vec[first_root] > this->depth_vec[second_root])
                {
                    this->parent_vec[second_root] = first_root;
                }
                else // == 树的深度相等,约定将第二个根挂接到第一个根,第一个根的深度加深一层
                {
                    this->parent_vec[second_root] = first_root;
                    ++this->depth_vec[first_root];
                }
            }
        }

        // 5. 构建结果
        unordered_map<int, vector<int>> root_vec{}; // 哈希表,记录 根节点值-该根节点下的元素向量,一个向量是一棵新树
        for (int i = 0; i < this->eq_rel_size; ++i) // 遍历元素值
        {
            int root = this->find_parent(i); // 取根节点
            root_vec[root].push_back(i);
        }

        for (const pair<int, vector<int>> &pair_tree : root_vec) // 遍历每棵树,加入到结果集
        {
            this->disjoint_set.insert(this->disjoint_set.begin(), pair_tree.second);
        }
    }

    // 获取并查集
    inline vector<vector<int>> get_disjoint_set() const
    {
        return this->disjoint_set;
    }

    // 打印并查集
    inline void print_disjoint_set() const
    {
        cout << "并查集: " << endl;
        for (const vector<int> set : this->disjoint_set)
        {
            for (const int num : set)
            {
                cout << num << " ";
            }
            cout << endl;
        }

        return;
    }

private:
    const int eq_rel_size;             // 等价关系元素值的大小/范围
    vector<pair<int, int>> eq_rel_vec; // 等价关系集合向量

    vector<int> parent_vec; // 记录元素父节点的向量
    vector<int> depth_vec;  // 记录元素深度的向量,约定元素值/树的根是索引,根的深度从0、1往上加

    vector<vector<int>> disjoint_set; // 并查集,并查集类固有的本质内容

    // 递归查找当前元素值的根节点
    int find_parent(int x)
    {
        // 1. 递归逻辑
        // 如果不是,parent[x] != x,则使用当前节点的父节点作为参数,调用当前函数,递归继续找爷节点:find_parent(parent[x])
        // 把找到的根节点记录在查找路径中每个节点的 元素父节点的向量 中:parent_vec[x] =
        // 相当于把该些节点,都挂接到根节点上,树变得扁平

        // 即路径压缩优化:在并查集中,每个元素都有一个父节点,通常在查找操作中,我们会沿着父节点链一直向上找到根节点
        // 这个过程就是在寻找元素所在集合的过程。但是,在普通的查找操作中,路径的长度可能会很长,导致后续的查找操作效率较低。
        // 路径压缩是一种优化技术,它的思想是:当我们在进行查找操作时,不仅找到元素所在集合的根节点,
        // 还顺便将经过的所有节点的父节点都设置为根节点。这样,当下次再次查找这些节点时,路径就会更短,查找效率就会更高。

        // 如:1为根节点,23为子节点,有1 - 2 - 3的三层树,从叶节点3开始找,找到1根节点,然后依次递归返回把2、3的根节点设置为1
        // 成为1 - 2,1 - 3的两层树
        if (parent_vec[x] != x)
        {
            parent_vec[x] = find_parent(parent_vec[x]);
        }

        // 1. 递归出口
        // 如果x的父节点是自己,说明它是根节点,返回
        // parent_vec[x] == x
        // 把return放在if会有到不了该条件if的警告:control reaches end of non-void function [-Wreturn-type]
        return parent_vec[x];
    }
};

int main()
{
    const int eq_rel_size = 9;                                                                          // 等价关系元素值的大小/范围
    const vector<pair<int, int>> eq_rel_vec = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {0, 2}, {4, 6}, {0, 8}}; // 等价关系集合向量,内容必须是0~ eq_rel_size - 1(并查集类的逻辑定义了)

    DisjointSet ds(eq_rel_size, eq_rel_vec); // 并查集对象
    ds.print_disjoint_set();                 // 打印并查集

    return 0;
}

Makefile

.PHONY : all
all : main.exe

main.exe : main.cpp
	g++ -o $@ $^

.PHONY : clean
clean :
	del *.exe

结果

在这里插入图片描述


总结

C++ 代码实例:并查集简单创建工具。


参考资料

  • 学校《高级算法设计与分析》课程课件的算法思路

作者的话

  • 感谢参考资料的作者/博主
  • 作者:夜悊
  • 版权所有,转载请注明出处,谢谢~
  • 如果文章对你有帮助,请点个赞或加个粉丝吧,你的支持就是作者的动力~
  • 文章在描述时有疑惑的地方,请留言,定会一一耐心讨论、解答
  • 文章在认识上有错误的地方, 敬请批评指正
  • 望读者们都能有所收获

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

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

相关文章

MATLAB - Gazebo 联合仿真 —— 使用 UR10 机械臂检测和采摘水果

系列文章目录 文章目录 系列文章目录前言一、设置 Gazebo 仿真环境二、在 Gazebo 中模拟和控制机器人2.1 概述2.2 任务调度器2.3 感知和目标生成系统2.4 运动规划2.5 机械臂和关节控制系统 三、分配用于控制机器人的参数3.1 定义机器人模型和运动规划参数&#xff0c;3.2 定义机…

基于野马算法的无人机航迹规划-附代码

基于野马算法的无人机航迹规划 文章目录 基于野马算法的无人机航迹规划1.野马搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用野马算法来优化无人机航迹规划。 1.野马搜索算法 …

基于向量加权平均算法的无人机航迹规划-附代码

基于向量加权平均算法的无人机航迹规划 文章目录 基于向量加权平均算法的无人机航迹规划1.向量加权平均搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用向量加权平均算法来优化无…

CSS 滚动捕获 Scroll Snap

CSS 滚动捕获 Scroll Snap CSS 滚动捕获允许开发者通过声明一些位置(或叫作捕获位置)来创建精准控制的滚动体验. 通常来说轮播图就是这种体验的例子, 在轮播图中, 用户只能停在图 A 或者图 B, 而不能停在 A 和 B 的中间. 比如平时用淘宝或小红书, 当你上滑到下一个推荐内容时…

分享90个节日庆典PPT,总有一款适合您

分享90个节日庆典PPT&#xff0c;总有一款适合您 PPT下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知识付费甚欢喜&#xff0c;为咱码农谋福利…

浅析C/C++的内存分段

这部分是计算机系统相关的知识&#xff0c;碍于本人才疏学浅&#xff0c;如本文存在疏漏或者错误&#xff0c;还望大佬能帮忙指出&#xff0c;感激不尽。 内存分段 从狭义上讲内存的分段可以分为堆、栈、数据段以及代码段&#xff08;内存映射区比较复杂&#xff0c;暂不涉及…

C++ Concurrency in Action 2nd Edition

《C Concurrency in Action - SECOND EDITION》的中文翻译-面圈网 (mianshigee.com) C/C 学习教程源码-C/C源码推荐-面试哥 (mianshigee.com) 作者正是为C11标准引入线程库的C标准委员会成员本人&#xff01;并且本书作者还编写了众多构成C标准的多线程和并发相关的提案、制定…

基于天鹰算法的无人机航迹规划-附代码

基于天鹰算法的无人机航迹规划 文章目录 基于天鹰算法的无人机航迹规划1.天鹰搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用天鹰算法来优化无人机航迹规划。 1.天鹰搜索算法 …

如何使用腾讯云+Picgo搭建图床

目录 一、进入腾讯云进行实名认证 二、领取免费存储额度 2.1新用户界面概览就可以领取 三、开始创建远端图床并生成秘钥等信息 3.1创建存储桶 3.2配置基本信息 3.3配置高级选项 3.4确认配置页面点击创建即可 3.5创建访问秘钥 3.6查看秘钥等信息 3.7查看桶名称 四、图…

《向量数据库指南》——开源框架NVIDIA Merlin 向量数据库Milvus

NVIDIA Merlin & Milvus 推荐系统 pipeline 中至关重要的一环便是为用户检索并找到最相关的商品。为了实现这一目标,通常会使用低维向量(embedding)表示商品,使用数据库存储及索引数据,最终对数据库中数据进行近似最近邻(ANN)搜索。这些向量表示是通过深度学习模型获…

Sentinel黑白名单授权规则解读

目录 基本介绍 代码实战 架构说明 RequestOriginParser的实现类 网关添加请求头 配置授权规则 基本介绍 授权规则可以对请求方来源做判断和控制。 很多时候&#xff0c;我们需要根据调用来源来判断该次请求是否允许放行&#xff0c;这时候可以使用 Sentinel 的来源…

zigbee路灯无线通讯机制

zigbee路灯无线通讯机制 wang20160630 前言 目前路灯上通讯主要有电力载波和无线通讯&#xff1b;各有利弊&#xff0c;众说纷纭&#xff1b;本文不对两种技术进行比较&#xff0c;也不讨论哪种好&#xff0c;毕竟同种通讯模块&#xff0c;有的开发出来稳定&#xff0c;有的…

cesium示例教程100+目录

cesium示例教程100旨在为开发者提供简单快捷的代码示例&#xff0c;复制即可用。在每一个示例中&#xff0c;解释相应的API知识点&#xff0c;做到简易实现&#xff0c;轻松学会。 文章目录 目录基础设置及界面配置设置材质material显示图形绘制图形加载文件数据加载各种地图综…

2023.11.6-分析 Gateway 和 VirtualService

2023.11.6-分析 Gateway 和 VirtualService 目录 本节实战 实战名称 正文 前面我们创建了一个 Gateway 和 VirtualService 对象&#xff0c;用来对外暴露应用&#xff0c;然后我们就可以通过 ingressgateway 来访问 Bookinfo 应用了。那么这两个资源对象是如何实现的呢&…

PyTorch深度学习实战——图像着色

PyTorch深度学习实战——图像着色 0. 前言1. 模型与数据集分析1.1 数据集介绍1.2 模型策略 2. 实现图像着色相关链接 0. 前言 图像着色指的是将黑白或灰度图像转换为彩色图像的过程&#xff0c;传统的图像处理技术通常基于直方图匹配和颜色传递的方法或基于用户交互的方法等完…

提升你的C#技能:掌握PrintDocument实现打印操作的秘诀

前言&#xff1a; 我们用C#在开发应用的时候&#xff0c;经常需要打印操作&#xff0c;比如你需要打印某些记录&#xff0c;或者是某些图像都需要用到打印的操作&#xff0c;比如我需要打印报警记录&#xff0c;按照指定的格式打印出来&#xff0c;我需要PrintDocument类&…

项目管理之如何识别并应对项目风险

项目风险管理是项目管理中不可忽视的环节&#xff0c;如何识别并应对项目的风险对于项目的成功实施至关重要。本文将介绍风险管理的流程、风险分解结构、定性及定量风险评估方法&#xff0c;以及消极和积极的风险应对策略&#xff0c;旨在帮助读者更好地理解和应对项目风险。 …

(1)(1.12) LeddarTech LeddarVu8

文章目录 前言 1 连接到自动驾驶仪 2 参数说明 前言 LeddarTech LeddarVu8 是一款长距离&#xff08;185m&#xff09;激光雷达&#xff0c;可在 16 度至 99 度视场范围内提供 8 个单独的距离&#xff0c;具体取决于所使用的型号。ArduPilot 始终使用所提供的 8 个距离中最…

VSCode设置中文语言界面(VScode设置其他语言界面)

一、下载中文插件 二、修改配置 1、使用快捷键 CtrlShiftP 显示出搜索框 2、然后输入 configure display language 3、点击 (中文简体) 需要修改的语言配置 三、重启 四、可能出现的问题 1、如果configure display language已经是中文配置&#xff0c;界面仍是英文 解决&a…

优化C++资源利用:探索高效内存管理技巧

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 我们之前在C语言中学习过动态内存开辟&#xff0c;使用malloc、calloc与realloc进行开辟&#xff0c;使用free进行堆上内存的释放。进入C后对于动态内存开辟我们又有了新的内容new与dele…