【数据结构与算法】并查集
admin
2024-03-19 17:08:50
0

目录

一、并查集原理

二、并查集实现

三、并查集应用

547. 省份数量 - 力扣(LeetCode)

总结


一、并查集原理

并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询两个元素是否在同一个集合中。

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

通俗的来说就是找朋友问题

假如现在有10个人,分别是{0,1,2,3,4,5,6,7,8,9}

他们有些人之间是朋友,现在将他们按照朋友圈划分为几个小集合

有一天7和4成为了好朋友,那么就需要将左侧两个朋友圈合并成为一个朋友圈

这就是并查集要解决的问题

并查集实际上是一个森林,它是由多棵树构成的

我们这里采用的表示树的方法与之前的二叉树不同,类似于堆,利用数组下标来确定父子关系

初始条件,每一个位置都是-1,代表每一个人都是一个小集合

然后合并朋友圈

仔细观察数组中存的值,可以得出以下结论: 1. 数组的下标对应集合中元素的编号 2. 数组中如果为负数,负号代表根,数字代表该集合中元素个数 3. 数组中如果为非负数,代表该元素双亲在数组中的下标

二、并查集实现

并查集的主要接口就只有两个Union和FindRoot

首先来说FindRoot

寻找根节点,什么属于根节点呢?

数组中存储的是负数的下标就是根的位置,这句话有一点绕

我们要找根节点,就是找数组不为负数的位置

    size_t FindRoot(int x){if(x < 0 || x >= _set.size()){throw invalid_argument("非法参数");return -1;}size_t parent = x;while(_set[parent] >= 0){parent = _set[parent];}return parent;}

有了FindRoot的基础之后Union,就容易理解了

Union是将两个集合合并,我们只要两个参数就可以x1,x2

我们先分别查找x1和x2的父亲,如果他们是同一个父亲,就不需要合并,如果他们的父亲不同,就将他们合并。

合并也十分简单

我们直接将x2父亲加到x1父亲上,并且将x2的父亲更改为x1的父亲

    void Union(int x1, int x2){size_t root1 = FindRoot(x1);size_t root2 = FindRoot(x2);_set[root1] += _set[root2];_set[root2] = root1;}

最后一个接口是SetCount,是用来计算并查集现在有几个集合的,也就是有几棵树

很简单,遇到数组中的负数,计数器就自增

    size_t SetSize(){size_t size = 0;for(const auto& e : _set){if(e < 0){size++;}}return size;}

完整代码:

#pragma once
#include 
#include 
#include 
using namespace std;class UnionFindSet
{
public:UnionFindSet(size_t n):_set(n, -1){}size_t FindRoot(int x){if(x < 0 || x >= _set.size()){throw invalid_argument("非法参数");return -1;}size_t parent = x;while(_set[parent] >= 0){parent = _set[parent];}return parent;}void Union(int x1, int x2){size_t root1 = FindRoot(x1);size_t root2 = FindRoot(x2);_set[root1] += _set[root2];_set[root2] = root1;}size_t SetSize(){size_t size = 0;for(const auto& e : _set){if(e < 0){size++;}}return size;}private:vector _set;
};

三、并查集应用

547. 省份数量 - 力扣(LeetCode)

这道题是典型的并查集应用,用来判断到底最后被划分为几个集合

class Solution {
public:int findCircleNum(vector>& isConnected) {vector ufs(isConnected.size(), -1);auto FindRoot = [&ufs](int x){while(ufs[x] >= 0){x = ufs[x];}return x;};for(size_t i = 0; i < isConnected.size(); i++){for(size_t j = 0; j < isConnected[i].size(); j++){if(isConnected[i][j] == 1){size_t root1 = FindRoot(i);size_t root2 = FindRoot(j);if(root1 != root2){ufs[root1] += ufs[root2];ufs[root2] = root1;}}}}size_t ans = 0;for(size_t i = 0; i < ufs.size(); i++){if(ufs[i] < 0)ans++;}return ans;}
};


总结

以上就是今天要讲的内容,本文仅仅讲解了并查集的简单实现及应用

相关内容

热门资讯

我家祖传炒面秘诀!伏天就靠这锅... “滋啦——”滚油爆香蒜末的瞬间,客厅里打游戏的儿子像装了弹簧,“嗖”地弹进厨房:“妈!今天炒面放腊肠...
郑州方中山胡辣汤:辣到流泪,配... 在河南早餐的丰富版图中,方中山胡辣汤占据着极为重要的地位,堪称 “硬核担当”。本文将深入探寻郑州方中...
冬天的第一碗:河南烩面,羊肉汤... 本文围绕冬天里的河南烩面展开,先是介绍了河南烩面作为冬日暖心美食的独特地位,点明其以羊肉汤为底、搭配...
“AI豚宝”亮相汉亮,探索长江... “在湖北避暑的绝佳去处有哪些?”当汉口的留学生们提出这个问题时,“AI豚宝”迅速展开回应,用流利的英...
原创 餐... 哪怕只有一个人吃饭,也要做到精致得体,美食、不仅仅是为了果腹,更是对生活的一种品味和追求,用心去过好...
2025年海南国际旅游岛欢乐节... 海南国际旅游岛欢乐节 第二十六届 盛夏八月,盛情海南欢乐启航!8月2日晚,2025年(第二十...
柬泰边境冲突期间,柬埔寨一退役... 柬埔寨和泰国的边境冲突随着两国达成停火协议而告一段落。在此期间,一名柬埔寨退役老兵在排水管里躲藏了6...
奇怪!内地奶茶巨头生意火爆却突... 近日,一则消息在社交平台上炸开了锅—— 中环兰桂坊附近的喜茶分店,竟「静悄悄」地消失了。 喜茶攻港失...
西北娃贝贝:黄花菜补脑益智三道... 很多家长常说: “娃写作业容易分神。” “记忆力不够好,上课容易走神。” 孩子大脑发育需要优质蛋白、...
西北娃贝贝:黄花菜配根茎蔬菜,... 冬季西北寒冷干燥,孩子容易手脚冰凉、胃口差。想让孩子长得快、少生病,餐桌上要多安排富含碳水和维生素的...
扑通一夏开桨啦!靖安县举办首届... 以“扑通一夏开桨啦!”为主题的2025 靖安 首届桨板潮玩季活动在仁首镇陈家畲举办。县领导钱骞、吴明...
旅行不只是行程安排,更是一种专... 大多数人对旅行社的印象,还停留在“安排交通住宿、拼好路线图、讲讲解说词”的阶段。 但如果你曾经作为企...
中国酱香白酒核心产区(仁怀)高... 8月2日,中国酱香白酒核心产区(仁怀)高质量发展座谈会在仁怀举行。全国酒类行业精英汇聚一堂,剖析行业...
"天下湖南人 喝酒喝... 一句"天下湖南人,喝酒喝武陵"正以前所未有的声量,响彻湖南大地!武陵酒全新品牌口号一经推出,便依托覆...