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

文章目录

  • 前言
  • 代码仓库
  • 代码
    • 说明
    • 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++ 代码实例:并查集简单创建工具。


参考资料

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

作者的话

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件测试|PO设计模式在 UI 自动化中的实践

PO的思想最早是2013年由IT大佬Martin Flower提出的&#xff1a;https://martinfowler.com/bliki/PageObject.html 没错&#xff0c;就是他 — 没错&#xff0c;就是他 — 在他的文章里有这样一张经典样图,图片中展示了测试代码中直接操作HTML元素和使用PO模式将page对象封装成…

“锡安主义”贝尔福宣言希伯来抵抗运动犹太启蒙改革运动奋锐党闪米特人雅利安人

目录 “锡安主义” 贝尔福宣言 希伯来抵抗运动 犹太启蒙改革运动 奋锐党 闪米特人 雅利安人 “锡安主义” “锡安主义”是一种政治和民族运动&#xff0c;旨在支持并促进犹太人建立自己的国家并在历史上与宗教上的祖先之地——巴勒斯坦地区建立一个独立的国家。这一运动…

C++11常用特性

目录 1、{}初始化 2、auto 3、decltype 4、nullptr 5、范围for 6、STL容器 7、右值引用 ①左值引用和右值引用 ②移动构造 ③移动赋值 ④万能引用与完美转发 8、新的类功能 9、可变模版参数 10、lambda表达式 捕捉列表的使用 [val]&#xff1a;传值捕捉 [&…

GPTZero:论文打假神器

记住这张脸他是全美学生的公敌。 别的学生在AI大浪潮间翻云覆雨&#xff0c;有的用GPT代写作业&#xff0c;有的用GPT代工论文&#xff0c;大家都忙的不亦乐乎。 正在大家都在欢呼雀跃跟作业拜拜时&#xff0c;就是这个小伙&#xff0c;普林斯顿大学的华裔小天才Edward Tian…

C++/Qt 小知识记录4

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识4 mysql导入*.sql文件提示连接超时等问题mysql局域网内访问VLC低版本的匹配QLineEdit的正则表达式限制获取windows下已加载磁盘盘符QLabel自动换行QElapsedTimer间隔计时自定义Class作为Key需要重载…

Spark SQL

Spark SQL 本文来自 B站 黑马程序员 - Spark教程 &#xff1a;原地址 第一章 SparkSql快速入门 1.1 什么是SparkSql Spark Sql is Spark’s module for working with strutured data. Spark Sql是Spark的模块&#xff0c;用于处理海量结构化数据 限量&#xff1a;结构化数据…

Tomcat的类加载器

详情可以参考&#xff1a;https://tomcat.apache.org/tomcat-10.1-doc/class-loader-howto.html 简要说明 Tomcat安装了多种类加载器&#xff0c;以便容器的不同部分、容器中的应用访问能够不同的类和资源。 在Java环境中&#xff0c;类加载器被组织为父-子树的形式。通常情况…

文件包含漏洞培训

CTF介绍 MISC(Miscellaneous)类型,即安全杂项,题目或涉及流量分析、电子取证、人肉搜索、数据分析等等。CRYPTO(Cryptography)类型,即密码学,题目考察各种加解密技术,包括古典加密技术、现代加密技术甚至出题者自创加密技术。PWN类型,PWN在黑客俚语中代表着攻破、取得权限…

技术分享 | app自动化测试(Android)-- 属性获取与断言

断言是 UI 自动化测试的三要素之一&#xff0c;是 UI 自动化不可或缺的部分。在使用定位器定位到元素后&#xff0c;通过脚本进行业务操作的交互&#xff0c;想要验证交互过程中的正确性就需要用到断言。 常规的UI自动化断言 分析正确的输出结果&#xff0c;常规的断言一般包…

Qt实现动态桌面小精灵(含源码)

目录 一、设计思路 二、部分源码演示 三、源码地址 🌈write in front🌈 🧸大家好,我是三雷科技.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由三雷科技原创 CSDN首发🐒 如需转载还请通知⚠️ 📝个人主页:三雷科技🧸—CSDN博客 🎁欢…

Leetcode刷题详解——字母大小写全排列

1. 题目链接&#xff1a;784. 字母大小写全排列 2. 题目描述&#xff1a; 给定一个字符串 s &#xff0c;通过将字符串 s 中的每个字母转变大小写&#xff0c;我们可以获得一个新的字符串。 返回 所有可能得到的字符串集合 。以 任意顺序 返回输出。 示例 1&#xff1a; 输入&…

渲染管线详解

光栅化的渲染管线一般分为三大阶段&#xff1a;应用程序阶段->几何阶段->光栅化阶段 也可以四大阶段&#xff1a; 应用程序阶段->几何阶段->光栅化阶段->逐片元操作阶段 更详细的流程如下&#xff1a; Vertex Specification&#xff08;顶点规范化&#xff09…

刚接触银行新业务测试的一些问题

在银行金融领域的测试工作&#xff0c;相信很多测试工程师都会遇到自己不熟悉的业务。然后开始看文档&#xff0c;问开发或者需求人员。搞懂了大概的流程&#xff0c;然后开始进行测试。 不过遇到复杂的业务情况时&#xff0c;真的很需要时间去梳理。而且测试环境的配置问题、不…

【自然语言处理】基于python的问答系统实现

一&#xff0c;文件准备 该问答系统是基于已知的问题和其一一对应的答案进行实现的。首先需要准备两个文本文件&#xff0c;分别命名为“question.txt”和“answer.txt”&#xff0c;分别是问题文件和答案文件&#xff0c;每一行是一个问题以及对应的答案。 问题文件: 中国的首…

在群晖NAS上使用AudioStation实现本地音频公网共享

文章目录 1. 本教程使用环境&#xff1a;2. 制作音频分享链接3. 制作永久固定音频分享链接&#xff1a; 之前文章我详细介绍了如何在公网环境下使用pc和移动端访问群晖Audio Station&#xff1a; 公网访问群晖audiostation听歌 - cpolar 极点云 群晖套件不仅能读写本地文件&a…

Spring Boot中配置多个数据源

配置数据源实际上就是配置多个数据库&#xff0c;在一个配置文件中配置多个数据库&#xff0c;这样做主要的好处有以下几点&#xff1a; 数据库隔离&#xff1a;通过配置多个数据源&#xff0c;可以将不同的业务数据存储在不同的数据库中&#xff0c;实现数据的隔离。这样可以…

安全易用的文件同步程序:Syncthing | 开源日报 No.70

syncthing/syncthing Stars: 55.0k License: MPL-2.0 Syncthing 是一个持续文件同步程序&#xff0c;它在两台或多台计算机之间同步文件。该项目的主要功能和核心优势包括&#xff1a; 安全防止数据丢失抵御攻击易于使用自动化操作&#xff0c;仅在必要时需要用户交互适合在各…

Pytest系列(16)- 分布式测试插件之pytest-xdist的详细使用

前言 平常我们功能测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟&#xff0c;如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时&#xff0c;会需要协调多个测试资源来把任务分成两部分&#xff0c;于是执行时间缩短一半&#…

船舶数据采集与数据模块解决方案

标准化信息处理单元原理样机初步方案&#xff1a; 1&#xff09;系统组成 标准化信息处理单元原理样机包含硬件部分和软件部分。 硬件部分包括集成电路板、电源模块、主控模块、采集模块、信息处理模块、通讯模块、I/O模块等。 软件部分包括协议统一标准化模块、设备互联互…

R语言将向量横向转换为单行数据框,随后整合数量不确定的数据框

vector1 c(1, “karthik”, “IT”) names(vector1) c(“id”, “name”, “branch”) df data.frame(as.list(vector1)) print(df) 先给向量的元素命名&#xff0c;然后转换为列表&#xff0c;最后转换为数据框。 我的需求大概是这个样子&#xff1a;数量不确定的仅有单行…