[数据结构高阶]并查集初识、手撕、可以解决哪类问题?

标题:[数据结构高阶]并查集初识、手撕、可以解决哪类问题?
@水墨不写bug


在这里插入图片描述


文章目录

  • 一、认识并查集
  • 二、模拟实现并查集
  • 三、用并查集解决问题
    • 1、[省份的数量](https://leetcode.cn/problems/number-of-provinces/)
    • 2、[等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/)
  • 四、并查集的路径压缩


一、认识并查集

一个考察队要去西部开发考察,这个考察队队员有10人,其中郑州4人,北京3人,西安3人。于是这三个城市的人由于生活习惯相似分别抱团,那么如何快速确定两个人是否属于同一个城市呢?并查集就可以。

并查集 :本质是一个森林(包含多棵树)。并且与堆类似,用下标表示关系。使用双亲表示法(只存储双亲)。
如何用数据结构表示并查集?
用一个线性结构(数组)表示。每一个位置都初始化为-1,表示10棵树:
在这里插入图片描述
假如0,6,7,8是郑州人1,4,9是北京人2,3,5是西安人,那么通过树形结构表示(默认下标最小的0,1,2作为小队长- - -根节点):
在这里插入图片描述
如果有新成员加入?
数组对应的队员的值存储的是队长的下标,队长的值的绝对值表示包括队长在内的小队成员个数。队长的值原来为-1,一个队员加入小队,队长的值+=队员的值(-1)|如果队员是队长,则+=(-m),然后队员的值修改为队长的值。

在线性的数组上,需要明确:

  • 1.一个位置值是负数,那它就是数的根,这个负数的绝对值就是这棵树的数据个数。
  • 2.一个位置值是正数,那这个位置存的是双亲的下标。

那么上图对应的线性结构是:
在这里插入图片描述

如果两队伍合并?
由于研究工作需要,北京人和郑州人需要合并,那么在数据结构上如何表示?
其实,把北京人合并入郑州,把郑州人合并入北京,没有本质区别。
假如把北京人合并入郑州,那么对应的树形结构变成:
在这里插入图片描述
那么对应的线性结构:
在这里插入图片描述
这就是并查集的加入一个成员,一个小队的操作。想要看两个队员是否在同一组,只需要不停找根,如果两个队员同根,那就在同一组。


二、模拟实现并查集

并查集可以通过一个STL的vector维护,具体实现思路已经在上文有所体现,于是在这里直接给出实现:

#pragma once
#include<iostream>
#include<vector>
namespace ddsm
{class UnionFindSet{public://根据并查集规则,初始化为-1UnionFindSet(int size):_ufs(size,-1){}//把两个集合【队伍】合并void Union(int x1,int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2)return;_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//找到一个元素所在的集合int FindRoot(int x){int parents = x;while (_ufs[parents] >= 0)parents = _ufs[parents];return parents;}//判断两个元素是否在同一个集合bool InSameSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}//返回集合的个数size_t Size(){size_t size = 0;for (int i = 0; i < _ufs.size(); ++i){if (_ufs[i] < 0)size++;}return size;}private:std::vector<int> _ufs;};
};

三、用并查集解决问题

通过以上例子可知,并查集一般可以解决一下问题:

  1. 查找元素属于哪个集合 --沿着数组表示树形关系以上一直找到根(即:树中中元素为负数的位置)
  2. 查看两个元素是否属于同一个集合 --沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在。
  3. 将两个集合归并成一个集合 --将两个集合中的元素合并将一个集合名称改成另一个集合的名称
  4. 集合的个数 --遍历数组,数组中元素为负数的个数即为集合的个数。

1、省份的数量

本题通过把同一省份的城市放在同一集合中,遍历所有城市链接情况,最后统计出省份(集合)的总数。
在这里插入图片描述
在这里插入图片描述
示例代码:

class UnionFindSet
{
public://根据并查集规则,初始化为-1UnionFindSet(int size):_ufs(size,-1){}//把两个集合【队伍】合并void Union(int x1,int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 == root2)return;_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//找到一个元素所在的集合int FindRoot(int x){int parents = x;while (_ufs[parents] >= 0)parents = _ufs[parents];return parents;}//判断两个元素是否在同一个集合bool InSameSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}//返回集合的个数size_t Size(){size_t size = 0;for (int i = 0; i < _ufs.size(); ++i){if (_ufs[i] < 0)size++;}return size;}
private:std::vector<int> _ufs;
};
class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {UnionFindSet ufs(isConnected.size());for(int i = 0;i < isConnected.size();++i){for(int j = 0;j < isConnected[i].size();++j){if(isConnected[i][j] == 1)ufs.Union(i,j);}}return ufs.Size();}
};

但是每次都手撕一个并查集,还是麻烦,那就面向过程的来维护并查集ufs,代码如下:

class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {vector<int> ufs(isConnected.size(),-1);auto findroot = [&ufs](int x){while(ufs[x] >= 0) x = ufs[x]; return x;};for(int i = 0;i < isConnected.size();++i){for(int j = 0;j < isConnected[i].size();++j){if(isConnected[i][j] == 1){int rooti = findroot(i);int rootj = findroot(j);if(rooti == rootj)continue;else{ufs[rooti] += ufs[rootj];ufs[rootj] = rooti;}}}}int ret = 0;for(int i = 0;i < ufs.size();++i)if(ufs[i] < 0)++ret;return ret;}
};

2、等式方程的可满足性

分两遍:
第一遍设置集合关系,哪一个元素属于哪一个集合先划分好;
第二遍查找相悖,有相悖,返回false;否则true。

在这里插入图片描述

在这里插入图片描述

class Solution {
public:bool equationsPossible(vector<string>& equations) {vector<int> ufs(26,-1);auto findroot = [&ufs](int x){while(ufs[x] >= 0)x = ufs[x];return x;};//第一遍先设置集合关系for(int i = 0;i < equations.size();++i){if(equations[i][1] == '='){int root1 = findroot(equations[i][0] - 'a');int root2 = findroot(equations[i][3] - 'a');if(root1 != root2){ufs[root1] += ufs[root2];ufs[root2] = root1;}}}//第二次再查找相悖关系for(int i = 0;i < equations.size();++i){if(equations[i][1] == '!'){int root1 = findroot(equations[i][0] - 'a');int root2 = findroot(equations[i][3] - 'a');if(root1 == root2){return false;}}}//没有相悖返回真return true;}
};

四、并查集的路径压缩

随着一棵树的高度增加,并查集的查找效率逐渐降低。路径压缩目的是减小树的高度,进而提高并查集查找效率。
路径压缩一般来说有两种思路:
**第一种:**每次查找一个位置,吧一个节点的位置直接更新到根。
**第二种:**每查找一个位置,把查找路径上的节点位置都更新到根。

到这里并查集结束了,并查集是为了给图做铺垫。


完~
转载请注明出处

在这里插入图片描述

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

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

相关文章

如何快速入门大模型?

学习大模型的流程是什么 &#xff1f; 提示词工程&#xff1a;只需掌握提问技巧即可使用大模型&#xff0c;通过优化提问方式获得更精准的模型输出套壳应用开发&#xff1a;在大模型生态上开发业务层产品&#xff08;如AI主播、AI小助手等&#xff09;&#xff0c;只需调用API…

《AI大模型应知应会100篇》第59篇:Flowise:无代码搭建大模型应用

第59篇&#xff1a;Flowise&#xff1a;无代码搭建大模型应用 摘要&#xff1a;本文将详细探讨 Flowise 无代码平台的核心特性、使用方法和最佳实践&#xff0c;提供从安装到部署的全流程指南&#xff0c;帮助开发者和非技术用户快速构建复杂的大模型应用。文章结合实战案例与配…

python打卡day23@浙大疏锦行

知识回顾: 1. 转化器和估计器的概念 2. 管道工程 3. ColumnTransformer和Pipeline类 作业&#xff1a; 整理下全部逻辑的先后顺序&#xff0c;看看能不能制作出适合所有机器学习的通用pipeline 一、导入数据库 import pandas as pd import numpy as np import matplo…

Vue.js框架的优缺点

别再让才华被埋没&#xff0c;别再让github 项目蒙尘&#xff01;github star 请点击 GitHub 在线专业服务直通车GitHub赋能精灵 - 艾米莉&#xff0c;立即加入这场席卷全球开发者的星光革命&#xff01;若你有快速提升github Star github 加星数的需求&#xff0c;访问taimili…

交易流水表的分库分表设计

交易流水表的分库分表设计需要结合业务特点、数据增长趋势和查询模式&#xff0c;以下是常见的分库分表策略及实施建议&#xff1a; 一、分库分表核心目标 解决性能瓶颈&#xff1a;应对高并发写入和查询压力。数据均衡分布&#xff1a;避免单库/单表数据倾斜。简化运维&#…

操作系统学习笔记第3章 (竟成)

第 3 章 内存管理 【考纲内容】 1.内存管理基础&#xff1a; 1.内存管理的基本概念&#xff1a;逻辑地址空间与物理地址空间&#xff1b;地址变换&#xff1b;内存共享&#xff1b;内存保护&#xff1b;内存分配与回收&#xff1b; 2.连续分配管理方式&#xff1b; 3.页式管理&…

中科院无人机导航物流配送的智能变革!LogisticsVLN:基于无人机视觉语言导航的低空终端配送系统

作者&#xff1a;Xinyuan Zhang, Yonglin Tian, Fei Lin, Yue Liu, Jing Ma, Kornlia Sra Szatmry, Fei-Yue Wang 单位&#xff1a;中国科学院大学人工智能学院&#xff0c;中科院自动化研究所多模态人工智能系统国家重点实验室&#xff0c;澳门科技大学创新工程学院工程科学系…

1.10-数据传输格式

1.10-数据传输格式 在对网站进行渗透测试时&#xff0c;使用目标服务器规定的数据传输格式来进行 payload 测试非常关键 如果不按规定格式发送数据&#xff0c;服务器可能直接拒绝请求或返回错误响应&#xff0c;比如&#xff1a; 接口要求 JSON 格式&#xff0c;而你用的是…

dfs 第一次加训 详解 下

目录 P1706 全排列问题 思路 B3618 寻找团伙 思路 B3621 枚举元组 思路 B3622 枚举子集&#xff08;递归实现指数型枚举&#xff09; 思路 B3623 枚举排列&#xff08;递归实现排列型枚举&#xff09; B3625 迷宫寻路 思路 P6183 [USACO10MAR] The Rock Game S 总结…

通信网络编程——JAVA

1.计算机网络 IP 定义与作用 &#xff1a;IP 地址是在网络中用于标识设备的数字标签&#xff0c;它允许网络中的设备之间相互定位和通信。每一个设备在特定网络环境下都有一个唯一的 IP 地址&#xff0c;以此来确定其在网络中的位置。 分类 &#xff1a;常见的 IP 地址分为 I…

#在 CentOS 7 中手动编译安装软件操作及原理

在 CentOS 7 中&#xff0c;手动编译安装软件&#xff08;即从源代码编译安装&#xff09;是一种高度灵活的方式&#xff0c;适用于需要定制化软件功能、优化性能或安装官方仓库未提供的软件版本的场景。以下是针对手动编译安装的详细说明&#xff0c;包括原理、步骤、注意事项…

菊厂0510面试手撕题目解答

题目 输入一个整数数组&#xff0c;返回该数组中最小差出现的次数。 示例1&#xff1a;输入&#xff1a;[1,3,7,5,9,12]&#xff0c;输出&#xff1a;4&#xff0c;最小差为2&#xff0c;共出现4次&#xff1b; 示例2&#xff1a;输入&#xff1a;[90,98,90,90,1,1]&#xf…

C——五子棋小游戏

前言 五子棋&#xff0c;又称连珠棋&#xff0c;是一种双人对弈的棋类游戏。游戏目标是在一个棋盘上&#xff0c;通过在横、竖、斜线上依次放置棋子&#xff0c;使自己的五个棋子连成一线&#xff0c;即横线、竖线或斜线&#xff0c;且无被对手堵住的空位&#xff0c;从而获胜…

ik 分词器 设置自定义词典

进入 ES 的安装目录&#xff0c;进入 /elasticsearch-8.10.0/plugins/ik/config/ 文件夹目录&#xff0c;打开 IKAnalyzer.cfg.xml 文件进行配置。 一、添加 自定义扩展词典 扩展词&#xff1a;就是不想哪些词分开&#xff0c;让他们成为一个词&#xff0c;比如“蒙的全是对…

Linux笔记---信号(上)

1. 信号的概念 Linux下的信号机制是一种进程间通信&#xff08;IPC&#xff09;的方式&#xff0c;用于在不同进程之间传递信息。 信号是一种异步的信息传递方式&#xff0c;这意味着发送信号的进程只发送由信号作为载体的命令&#xff0c;而并不关心接收信号的进程如何处置这…

UG 二次开发- UG内部调用DLL

【1】用VS新建一个dll工程 将项目设置为x64平台&#xff08;这步很重要&#xff0c;否则程序无法编译成功&#xff09; 【2】添加UG头文件目录&#xff0c;属性页->C/C->常规->附加包含目录 【3】添加UG库所在目录&#xff0c;属性页->链接器->常规->附加库目…

wordcount在mapreduce的例子

1.启动集群 2.创建项目 项目结构为&#xff1a; 3.pom.xml文件为 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://mave…

智慧城市综合运营管理系统Axure原型

这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面&#xff0c;通过统一标准接入各类业务系统&#xff0c;实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心&#xff0c;为其提供一个直观、便捷、高效的协同服务平台…

Go语言:json 作用和语法

在 Go 语言中&#xff0c;JSON 字段&#xff08;也称为 JSON Tag&#xff09;是附加在结构体字段上的元数据&#xff0c;用于控制该字段在 JSON 编码&#xff08;序列化&#xff09;和解码&#xff08;反序列化&#xff09; 时的行为。它的语法是&#xff1a; type StructName…

MATLAB复制Excel数据到指定区域

Matlab中如何将Excel表中的265-528行F-AA列数据复制到1-263行AE-AZ中 版本&#xff1a;MatlabR2018b clc; clear; %旧Excel文件名 oldFile ; %新Excel文件名 newFile ; % 工作表名称&#xff08;旧表和新表一致&#xff09; sheetName Sheet1; % 旧文件中待复制的数据范…