C++的数据结构(十八):并查集

        并查集(Union-Find)是一种用于处理一些不交集(Disjoint Sets)问题的数据结构。它主要支持两种操作:合并集合(Union)和查找元素所属集合(Find)。在解决诸如连通性问题、网络中的群组问题等场景时,并查集表现出色。

        并查集的基本思想是使用一个数组来表示所有的元素,数组的每个索引对应一个元素,数组的值则表示该元素所属的集合的代表元素(也称为父节点或根节点)。初始时,每个元素都自成一个集合,所以数组的每个值都初始化为其自身的索引。

        查找操作(Find)用于确定两个元素是否属于同一集合,这通常通过递归地查找元素的父节点,直到找到根节点(父节点为自身的节点)为止。在查找过程中,为了加速后续的查找操作,通常还会进行路径压缩,即将查找路径上的所有节点直接指向根节点。

        合并操作(Union)用于将两个集合合并为一个集合。这通常通过将其中一个集合的代表元素设置为另一个集合的代表元素的子节点来实现。在实际应用中,为了保持树的平衡性,常常选择秩(rank)较小的树的根节点作为子节点,秩可以简单理解为树的高度的一个上界。

        下面是一个简单的C++示例,展示了并查集的基本操作,代码如下。

#include <iostream>
#include <vector>
using namespace std; 
class UnionFind {
private:vector<int> parent; // 父节点数组vector<int> rank;   // 秩数组public:UnionFind(int n) {parent.resize(n);rank.resize(n, 0);for (int i = 0; i < n; ++i) {parent[i] = i;}}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) {if (rank[rootX] < rank[rootY]) {parent[rootX] = rootY;} else if (rank[rootX] > rank[rootY]) {parent[rootY] = rootX;} else {parent[rootY] = rootX;rank[rootX]++;}}}bool isConnected(int x, int y) {return find(x) == find(y);}
};int main() {UnionFind uf(5); // 初始化一个包含5个元素的并查集uf.unite(0, 1);  // 合并0和1所在的集合uf.unite(2, 3);  // 合并2和3所在的集合cout << uf.isConnected(0, 1) << endl; // 输出1,表示0和1连通cout << uf.isConnected(0, 2) << endl; // 输出0,表示0和2不连通uf.unite(1, 3);  // 合并1和3所在的集合,由于0和1连通,2和3连通,所以合并后0-1-3-2都连通cout << uf.isConnected(0, 2) << endl; // 输出1,表示0和2连通return 0;
}

         在上面的示例中,我们首先创建了一个包含5个元素的并查集。然后,我们合并了0和1所在的集合,以及2和3所在的集合。接着,我们检查0和1是否连通(输出1表示连通),以及0和2是否连通(输出0表示不连通)。最后,我们合并了1和3所在的集合,由于之前0和1连通,2和3连通,所以合并后0-1-3-2都连通,再次检查0和2是否连通时输出1表示连通。

        并查集的应用实例:朋友圈划分。      

        假设有n个人,给定他们的m个朋友关系对,如果两个人是朋友,那么他们属于同一个朋友圈。请编写一个程序,输出最终每个人所属的朋友圈编号。为了解决这个问题,我们可以使用并查集数据结构。将每个人视为一个节点,朋友关系对视为边,通过合并操作将属于同一个朋友圈的人合并到同一个集合中。最后,通过查找操作确定每个人所属的朋友圈编号。代码如下。

#include <iostream>
#include <vector>
using namespace std;
class UnionFind {
private:vector<int> parent; // 父节点数组,初始时每个节点的父节点是自己vector<int> rank;   // 秩数组,记录每个节点对应的树的秩public:UnionFind(int n) {parent.resize(n);rank.resize(n, 0);for (int i = 0; i < n; ++i) {parent[i] = i; // 初始化父节点为自己}}int find(int x) {if (x != parent[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) {if (rank[rootX] < rank[rootY]) {parent[rootX] = rootY;} else if (rank[rootX] > rank[rootY]) {parent[rootY] = rootX;} else {parent[rootY] = rootX;rank[rootX]++;}}}
};int main() {int n, m;cin >> n >> m; // 输入人数和朋友关系对数UnionFind uf(n); // 初始化并查集for (int i = 0; i < m; ++i) {int x, y;std::cin >> x >> y; // 输入朋友关系对uf.unite(x - 1, y - 1); // 注意从0开始编号,需要减1转换为从1开始的编号}vector<int> circles(n); // 存储每个人所属的朋友圈编号for (int i = 0; i < n; ++i) {circles[i] = uf.find(i); // 通过查找操作确定每个人所属的朋友圈编号circles[i]++; // 由于我们是从0开始编号的,而题目要求从1开始编号,所以加1}// 输出每个人所属的朋友圈编号for (int i = 0; i < n; ++i) {cout << "第 " << i + 1 << " 人属于朋友圈 " << circles[i] << endl;}return 0;
}

        假设输入如下:

        4 3
        1 2
        2 3
        4 1

        表示有4个人,3对朋友关系。运行上述代码后,输出结果如下图所示.

        这表明所有人都属于同一个朋友圈,编号为1。

         通过并查集的应用,我们可以高效地解决朋友圈划分这类连通性问题。并查集通过合并和查找操作,能够快速地将元素分组,并确定元素之间的关联关系。在实际应用中,并查集还可以用于解决网络中的群组划分、图像分割等问题。

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

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

相关文章

牛客小白月赛94( 6 / 6 )

小苯的九宫格 #include<bits/stdc.h> using namespace std; map<int,int>mp; void solve(){for(int i1;i<9;i){int x;cin>>x;mp[i]x;}string s;cin>>s;for(auto i:s){cout<<mp[i-0];} } int main(){ios::sync_with_stdio(false), cin.tie(0)…

Ruoyi框架学习——权限管理

权限分类 菜单权限&#xff1a;用户登录系统之后能看到哪些菜单按钮权限&#xff1a;用户在一个页面上能看到哪些按钮&#xff0c;比如新增、删除等按钮接口权限&#xff1a;用户带着认证信息请求后端接口&#xff0c;是否有权限访问&#xff0c;该接口和前端页面上的按钮一一对…

AI生成内容检测|Fast-DetectGPT:通过条件概率曲率对机器生成文本进行有效的零样本检测

【摘要】大型语言模型 (LLM) 已显示出生成流畅且有说服力的内容的能力&#xff0c;这既带来了生产力机会&#xff0c;也带来了社会风险。要构建值得信赖的 AI 系统&#xff0c;必须区分机器生成的内容和人类创作的内容。领先的零样本检测器 DetectGPT 展示了值得称赞的性能&…

Github 2024-05-25 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2024-05-25统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Svelte项目1TypeScript项目1Python项目1Go项目1Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust…

建筑工程乙级资质全面解析:设计能力与业务范畴

建筑工程乙级资质全面解析&#xff1a;设计能力与业务范畴 建筑工程乙级资质是中国建筑业中一项重要的资质认证&#xff0c;标志着设计单位具备一定规模和水平的专业技术力量&#xff0c;能够在限定范围内承担建筑设计及相关工程服务。本文将深入解析乙级资质的设计能力与业务…

如果有多个文件夹,怎么快速获得文件夹的名字呢

上一篇写到怎么批量建立文件夹&#xff0c;那么怎么获取批量文件夹的名字呢&#xff1f; 一、啊这&#xff0c;这真是一个好问题二、这个得用Python&#xff08;文本末尾有打包程序&#xff0c;点击链接运行就可以了&#xff09;&#xff08;1&#xff09;首先建立一个py文件&a…

博客系统(Servlet实现)

目录 1.准备工作 2.数据库设计 2.1表设计 2.2封装数据库操作代码 2.3创建 Blog 类 和 User 类 2.4创建 BlogDao 类和 UserDao 类 3.读取博客列表功能 3.1约定前后端交互接口 3.2实现服务器代码 3.3实现客户端代码 4.实现博客详情 4.1约定前后端交互接口 4.2实现服…

AGI技术与原理浅析:曙光还是迷失?

前言&#xff1a;回顾以往博客文章&#xff0c;最近一次更新在2020-07&#xff0c;内容以机器学习、深度学习、CV、Slam为主&#xff0c;顺带夹杂个人感悟。笔者并非算法科班出身&#xff0c;本科学制药、研究生学金融&#xff0c;最原始的算法积累都来源于网络&#xff0c;当时…

Android android.os.DeadObjectException aidl通信异常分析及解决

问题描述 做一款音乐播放应用&#xff0c;播放服务是通过AIDL形式对外暴露&#xff0c;允许跨进程调用且多个App同时操作音乐播放&#xff0c;偶现android.os.DeadObjectException问题 12-15 09:28:12.371: W/System.err(5412): android.os.DeadObjectException 12-15 09:28:…

乡村振兴与乡村文化传承创新:保护和传承乡村文化,推动乡村文化创新发展,打造具有文化魅力的美丽乡村

一、引言 在当代中国&#xff0c;乡村振兴已成为国家发展的重要战略之一。乡村不仅是自然资源的富集地&#xff0c;更是中华优秀传统文化的发源地。保护和传承乡村文化&#xff0c;推动乡村文化创新发展&#xff0c;对于打造具有文化魅力的美丽乡村&#xff0c;实现乡村全面振…

SSMP整合案例第三步 业务层service开发及基于Mybatis的接口功能拓展

业务层开发 对于业务层的制作有个误区 Service层接口定义与数据层接口定义具有较大差别 不要混用 业务层接口关注的是业务名称 数据层接口关注的是数据层名称 操作是不难 但是有些东西还是要掌握的 业务层接口如果是业务方法 就按照业务名称来代替 如果是数据操作 直接用…

本地部署Whisper实现语言转文字

文章目录 本地部署Whisper实现语言转文字1.前置条件2.安装chocolatey3.安装ffmpeg4.安装whisper5.测试用例6.命令行用法7.本地硬件受限&#xff0c;借用hugging face资源进行转译 本地部署Whisper实现语言转文字 1.前置条件 环境windows10 64位 2.安装chocolatey 安装chocol…

【调试笔记(目录)】

调试笔记-系列文章目录 第一章 Windows 环境 [1001] 使用VS2019编译edk2&#xff08;上&#xff09; [1002] 使用VS2019编译edk2&#xff08;下&#xff09; [1003] 调试 ExdiGdbSvr [1004] WSL 修改已安装发行版名称 [1005] 配置 QEMU/x86_64 运行 OpenWrt-23.05 发行版并搭…

mysql驱动版本变更导致查询数据结果一直是空

1 引言 最近接手了一个已离职同事的java项目&#xff0c;这个项目中原来使用了自己的mysql驱动版本&#xff0c;并未使用公司公共依赖中的版本号。我想为了统一版本号&#xff0c;就将当前项目中pom文件中mysql的版本号verson给去除了。没怎么自测&#xff0c;就直接发到测试环…

零基础学Java第二十二天之IO流之内存流,打印流,随机流

IO流之内存流&#xff0c;打印流&#xff0c;随机流 1、内存流 1、理解 内存流"&#xff08;Memory Stream&#xff09;在计算机编程中通常指的是一种特殊的数据流&#xff0c;它在内存中存储和操作数据&#xff0c;而不是在外部存储&#xff08;如硬盘、网络等&#xf…

申请轻纺行业工程设计资乙级对企业有什么要求

注册资金&#xff1a;企业的注册资金应至少达到三百万&#xff0c;这是衡量企业经济实力和承担风险能力的重要指标。独立法人资格&#xff1a;企业应具备独立的法人资格&#xff0c;能够独立承担民事责任&#xff0c;并具备相应的经营自主权。专业技术人员配备&#xff1a;企业…

前端框架选择指南:React vs Vue vs Angular

选择前端框架时&#xff0c;React、Vue 和 Angular 都是流行的选择&#xff0c;各有优缺点。我们可以从各个维度进行比较和选择&#xff1a; React 核心理念&#xff1a; 组件化开发&#xff0c;专注于视图层。学习曲线&#xff1a; 相对平缓&#xff0c;因为重点在于JSX和组…

免费的八字软件

无敌八字排盘软件完全免费使用&#xff0c;即使用不需要付费且无任何限制。同时推出手机版电脑版&#xff0c;两版本数据互通互用&#xff0c;即电脑版的数据可以备份到手机版上导入&#xff0c;手机版的数据也可以备份到电脑版上恢复导入&#xff0c;方便手机和电脑共用的朋友…

Golang实现递归复制文件夹

代码 package zdpgo_fileimport ("errors""os""path/filepath""strings" )// CopyDir 复制文件夹 // param srcPath 源文件夹 // param desPath 目标文件夹 // return error 错误信息 func CopyDir(srcPath, desPath string) error {…

在Java中实现泛型(Generics)的深入解析

在Java中&#xff0c;泛型&#xff08;Generics&#xff09;是一个强大的工具&#xff0c;它允许我们在编译时定义类型参数&#xff0c;使代码更加灵活、可重用和类型安全。下面&#xff0c;我将从技术难点、面试官关注点、回答吸引力以及代码举例四个方面&#xff0c;详细解析…