C++并查集

article/2025/8/26 23:45:39

文章目录

  • 并查集的原理
  • 并查集的实现代码
  • 并查集的典型应用


并查集的原理

在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-find set)。
在这里插入图片描述

并查集一般可以解决以下问题:

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

并查集的实现代码

使用数组(vector)实现:

#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
class UnionFindSet
{
public:UnionFindSet(size_t n){_ufs.resize(n, -1);}//将x2合并到x1void Union(int x1, int x2){assert(x1 < _ufs.size());assert(x2 < _ufs.size());//找到它们的根,然后将其中一个根与另一个根相连int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 != root2){_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}}int FindRoot(int x){assert(x < _ufs.size());while (_ufs[x] >= 0){x = _ufs[x];}return x;}//获取有几个集合,也就是根的数量//根对应的值为负数int GetSize(){int n = 0;for (auto& e : _ufs){if (e < 0){n++;}}return n;}
private:vector<int> _ufs;
};

使用节点实现:

template<class V>
class Node
{
public:Node(V v):value(v){}
private:V value;
};//用链表实现的并查集
template<class V>
class UnionFindNodeSet
{
public:UnionFindNodeSet(vector<V>values){for (auto& value : values){Node<V>* node=new Node<V>(value);nodes.insert(make_pair(value, node));parents.insert(make_pair(node, node));sizeMap.insert(make_pair(node, 1));}}//从cur一直往上找最顶上的父节点//同时把路径上的点都与该父节点相连//为了减少下次查找的路径Node<V>* findFather(Node<V>* cur){//记录路径查找的路径stack<Node<V>*>path;while (cur != parents[cur]){path.push(cur);cur = parents[cur];}//找到头结点,将路径上的节点插到头结点下面while (!path.empty()){Node<V>* ret = path.top();path.pop();parents.insert(make_pair(ret, cur));}return cur;}bool isSameSet(V a, V b){if (!nodes.count(a) || !nodes.count(b)){return false;}return findFather(nodes[a])==findFather(nodes[b]);}void Union(V a, V b){if (!nodes.count(a) || !nodes.count(b)){return ;}Node<V>*aHead = findFather(nodes[a]);Node<V>*bHead = findFather(nodes[b]);if (aHead != bHead){int aSetSize = sizeMap[aHead];int bSetSize = sizeMap[bHead];Node<V>*bigNode = aSetSize >= bSetSize ? aHead : bHead;Node<V>*smallNode = bigNode == aHead?bHead : aHead;parents[smallNode]=bigNode;sizeMap[bigNode] = aSetSize + bSetSize;sizeMap.erase(smallNode);}}//获取有几个集合,也就是根的数量//在parents,其映射为自己int GetSize(){int n = 0;auto it = parents.begin();while(it!=parents.end()){if (it->first==it->second){n++;}it++;}return n;}private://映射当前值和对应的节点map<V, Node<V>*>nodes;//映射node和其父节点map<Node<V>*, Node<V>*>parents;//记录当前节点对应集合中节点的个数map<Node<V>*, int>sizeMap;
};

在这里插入图片描述


并查集的典型应用

省份数量
相连的省份他们都在一个集合里,所以只需要用并查集统计一共有几个集合即可。

class UnionFindSet
{
public:UnionFindSet(size_t n){_ufs.resize(n, -1);}//将x2合并到x1void Union(int x1, int x2){assert(x1 < _ufs.size());assert(x2 < _ufs.size());int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 != root2){_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}}int FindRoot(int x){assert(x < _ufs.size());while (_ufs[x] >= 0){x = _ufs[x];}return x;}int GetSize(){int n=0;for(auto&e:_ufs){if(e<0){n++;}}return n;}
private: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.size();j++){if(isConnected[i][j]==1){ufs.Union(i,j);}}}return ufs.GetSize();}
};

等式方程的可满足性
如果两个字符相等,则放入同一个集合之中。
如果两个字符不相等,它们应当在不同的集合中,此时查找它们所在集合的根,如果相同则说明这两个字符在同一个集合中,返回false。

class UnionFindSet
{
public:UnionFindSet(size_t n){_ufs.resize(n, -1);}//将x2合并到x1void Union(int x1, int x2){assert(x1 < _ufs.size());assert(x2 < _ufs.size());int root1 = FindRoot(x1);int root2 = FindRoot(x2);if (root1 != root2){_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}}int FindRoot(int x){assert(x < _ufs.size());while (_ufs[x] >= 0){x = _ufs[x];}return x;}
private:vector<int> _ufs;
};
class Solution {
public:bool equationsPossible(vector<string>& equations) {UnionFindSet ufs(26);//第一遍先把相等的值合并到一个集合for(auto& str:equations){if(str[1]=='='){ufs.Union(str[0]-'a',str[3]-'a');}}//第二遍把不相等的值判断在不在一个集合,如果在就逻辑相悖,返回falsefor(auto& str:equations){if(str[1]=='!'){if(ufs.FindRoot(str[0]-'a')==ufs.FindRoot(str[3]-'a')){return false;}}}return true;}
};

http://chatgpt.dhexx.cn/article/EuGAph40.shtml

相关文章

c++并查集(详细总结)

老话重谈&#xff0c;先看定义 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合&#xff08;disjoint sets&#xff09;的合并及查询问题。常常在使用中以森林来表示。 首先得明白一些概念&#xff1a; 什么是树&#xff0c;什么是森林&#xff08;由树组成的叫…

Java——并查集

概念 当我们将多个元素分配到不同的集合中&#xff0c;这些集合有的是相关的&#xff0c;有的是不相关的。并查集就是用来查找两个元素是否在同一个集合中的 其主要实现方式是&#xff1a;将所有的元素以下标的形式存储在数组中。例如一共有十个人&#xff0c;那么就将这些人…

并查集Python版

以下来自于leetcode 使用数据结构&#xff1a;并查集 思路&#xff1a;由于相等关系具有传递性&#xff0c;所有相等的变量属于同一个集合&#xff1b;只关心连通性&#xff0c;不关心距离&#xff0c;因此很容易想到并查集。&#xff08;很容易嘛&#xff0c;反正我想不到&am…

并查集详解

文章目录 并查集一、简介1.定义2. 并查集的实现与优化 二、练习1.合并集合2.连通块中点的数量3. 食物链 三、总结 并查集 一、简介 1.定义 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题&#xff08;即所谓的并、查&#xff09;。比如说&am…

带权并查集

带权并查集需要先理解一般的并查集&#xff0c;不明白的可自行先搜索有关内容 一般的并查集主要记录节点之间的链接关系&#xff0c;而没有其他的具体的信息&#xff0c;仅仅代表某个节点与其父节点之间存在联系&#xff0c;它多用来判断图的连通性&#xff0c;如下图所示&…

并查集,不就一并和一查?

什么是并查集 并查集这种数据结构&#xff0c;可能出现的频率不是那么高&#xff0c;但是还会经常性的见到&#xff0c;其理解学习起来非常容易&#xff0c;通过本文&#xff0c;一定能够轻轻松松搞定并查集&#xff01; 对于一种数据结构&#xff0c;肯定是有自己的应用场景和…

数据结构——并查集

并查集是一种数据结构&#xff0c;是树的一种应用&#xff0c;用于处理一些不交集&#xff08;一系列没有重复元素的集合&#xff09;的合并以及查询问题。并查集支持如下操作&#xff1a; 查询&#xff1a;查询某个元素属于哪个集合&#xff0c;通常是返回集合内的一个“代表…

并查集详解(C/C++)

并查集算法详解&#xff08;C&#xff09; 并查集基础并查集是什么&#xff1f;并查集的作用是什么&#xff1f;并查集的结构合并查询 代码实现优化1&#xff1a;避免退化&#xff08;按秩合并&#xff09;代码优化 优化2&#xff1a;路径压缩代码优化 最终代码实现复杂度分析经…

并查集及其应用

并查集的基本操作: 1.合并两个集合 2.查询两个元素的祖宗节点 扩展: 1.记录每个集合的大小 将集合大小绑定到代表元素节点上 就是并查集的思想 (不是每个元素都是正确的 但是代表元素是正确的) 2.记录每个点到根节点的距离 绑定到每个元素身上 因为每个元素到根节点的距离…

并查集(Union-Find) (图文详解)

文章目录 并查集基础知识定义C实现优化 精选算法题(Java实现)实现并查集交换字符串中的元素最长连续序列 - 字节面试常考连通网络的操作次数最大岛屿数量 (三种解法)省份数量冗余连接冗余连接Ⅱ情侣牵手(困难)移除最多的同行或同列石头等式方程的可满足性 结语 并查集基础知识 …

什么是 “并查集” ?

导语&#xff1a;并查集是一种精巧的算法&#xff0c;本身并不难理解&#xff0c;却很常用&#xff0c;在许多场景下都能找到并查集的身影。 本文作者封承成&#xff0c;年仅12岁&#xff0c;非常感谢他的投稿。 并查集是什么 并查集&#xff0c;是一种判断“远房亲戚”的算法。…

并查集(Disjoint Set)

目录 ❤️什么是并查集&#xff1f; &#x1f3b6;实现方法1 &#x1f414;实现方法2 &#x1f383;题目1 ❤️什么是并查集&#xff1f; 并查集是一种数据结构&#xff0c;用于处理一些不交集&#xff08;Disjoint sets&#xff0c;一系列没有重复元素的集合&#xff09;的…

并查集

参考 https://www.cnblogs.com/asdfknjhu/p/12515480.html https://www.bilibili.com/video/BV13t411v7Fs?p3 https://leetcode-cn.com/problems/number-of-provinces/solution/python-duo-tu-xiang-jie-bing-cha-ji-by-m-vjdr/ 一、基本概念 并查集是一种数据结构 并查集这…

并查集(详细解释+完整C语言代码)

目录 1概论 2.树的表现形式 3.代码实现 3.1创立集合 3.2合并 3.3查询 3.4路径压缩 第一个方法&#xff1a;查找时优化 第二个方法&#xff1a;合并时优化&#xff08;加权标记法&#xff09; 4.完整代码 4.1优化前 4.2优化后 1概论 并查集是一种十分精巧且实用的树形…

时间序列预测的一般步骤

一、ARIMA模型概述 ​​ ARMA模型就是AR和MA的简单结合&#xff0c;同时包含了历史数值项和错误项。由于AR和MA模型都对时间序列有平稳性要求&#xff0c;ARMA模型也存在这个限制&#xff0c;因此我们将其拓展到ARIMA模型&#xff0c;其可以解决非平稳性问题。引入的差分概念是…

时间序列预测算法总结

时间序列算法 time series data mining 主要包括decompose&#xff08;分析数据的各个成分&#xff0c;例如趋势&#xff0c;周期性&#xff09;&#xff0c;prediction&#xff08;预测未来的值&#xff09;&#xff0c;classification&#xff08;对有序数据序列的feature提…

基于深度学习的时间序列预测

# 技术黑板报 # 第十一期 推荐阅读时长&#xff1a;15min 前言 时间序列建模历来是学术和工业界的关键领域&#xff0c;比如用于气候建模、生物科学和医学等主题应用&#xff0c;零售业的商业决策和金融等。虽然传统的统计方法侧重于从领域专业知识层面提供参数模型&#xff0…

预测类问题中的时间序列预测模型

前言&#xff1a;时间序列预测模型适用于含有时间变量的模型预测&#xff0c;对中短期的预测有着较好的结果&#xff0c;对长期预测不适用。本文重点介绍ARIMA模型的原理及代码实现。 其他模型总结&#xff1a;​【Python】Python中的经典时间序列预测模型总结_风度78的博客-C…

Transformer 在时间序列预测中的应用

2017年&#xff0c;Google的一篇 Attention Is All You Need 为我们带来了Transformer&#xff0c;其在NLP领域的重大成功展示了它对时序数据的强大建模能力&#xff0c;自然有人想要把Transformer应用到时序数据预测上。在Transformer的基础上构建时序预测能力可以突破以往的诸…

【推荐收藏】11种比较常用的时间序列预测模型

时间序列及其预测是日常工作中建模&#xff0c;分析&#xff0c;预测的重要组成部分。 本文我们将从0开始介绍时间序列的含义&#xff0c;模型及其分析及其常用的预测模型。 文章目录 交流时间序列定义时间序列预测模型与方法原始数据朴素法简单平均法移动平均法指数平滑法一次…