老话重谈,先看定义

并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示。

首先得明白一些概念:
什么是树,什么是森林(由树组成的叫森林hh),什么是集合
这些问题是其他范畴的知识,就不过多累赘了,不了解的同学建议提前了解先。

下面我们切入重点

1、并查集

首先,我个人认为并查集在逻辑上是一个森林,该森林内由一棵或多棵数组成,如下举个例子

这三棵树可以组成一个森林,而这个森林可以叫并查集,每棵树可以称为并查集分量,这是逻辑上的理解

显式上理解,大部分情况并查集是以数组的方式进行存储的

有一些如下性质

  • 每一个并查集分量(也就是每一棵树)都有一个根结点,比如上面三棵树的根结点分别是1,2,10
  • 所属同一个并查集分量的结点的根结点是相同的,比如6,7,8的根结点都是10,所以这三个结点位于同一个并查集分量内,也就是同一颗树上
  • 并查集每一个分量都是相互独立,互不影响的!
  • 并查集内所有节点的值一定是互不相同的

2、常用并查集方法

在讲方法之前我们需要定义一些并查集需要用到的数据

数据存储 作用及举例
parent[] parent[ i ] = j 表示 节点 i 的父节点是 j(比如上面根结点为10的那棵树,有 parent[ 7 ] = 6 , parent[ 6 ] = 10 …)
count 是一个int类型的变量,表示该并查集内有多少个并查集分量,也就是说并查集这个森林里面有多少课树(比如上面的例子中有三个树,所以count=3)

我们先定义并查集的数据结构代码(这里采用c++)

class DisjointSets{public:// 给个默认值,默认是10int count = 10;// vector的好处是可以动态修复数组大小vector<int> parent;// 类的有参构造方法DisjointSets(int count){this->count = count;// 对parent数组进行初始化for(int i=0;i<=count;++i)// 默认这个森林有count棵树,//而且每棵树只有一个节点,也就是// 根结点,默认根结点的父节点是根结点本身parent[i] = i;}// 类的析构函数,销毁类实例前调用~DisjointSets(){}// 并查集的方法定义-----------------// 查找一个节点所属树的根节点int findParentNode(int x);// 合并两棵树void unionSetNode(int x,int y);
};

2.1、并查集——查找某个节点的根结点

int DisjointSets::findParentNode(int x){// 如果x的父节点还是x,说明x就是根节点if(x == this->parent[x]) return x;// 否则继续找return findParentNode(this->parent[x]);
}

2.2、并查集——合并两个并查集分量(合并两棵树)

有些时候我们需要将一些并查集分量进行合并,以满足需求

将根节点为 2 的树 合并到 根节点 为 1 的树上。
合并完成后 ,根节点 2 的父节点 不再是 2 了,而是 1,如下

再合并之前我们还需要判断一些 需要合并的两个节点是否是同一个并查集分量(同一棵树上)
代码如下:

void DisjointSets::unionSetNode(int x,int y){// 先分别获取到 x 节点和 y节点 所属树的根节点int root_x = this->findParentNode(x);int root_y = this->findParentNode(y);// 如果两个节点的根节点相等,就不需要合并,是同一颗树的节点if(root_x == root_y) return;// 如果不相等,由于是y所属树合并到 x所属树上// 所以让 y所属树的根节点的父节点赋值为x所属树的根节点this->parent[root_y] = root_x;// 同时, 此时森林少了一颗树--this->count;
}

2.3、并查集查找根节点优化——路径压缩算法

那么什么叫路径压缩内,我们先看看传统寻找某个节点所属树的根节点方法

相当于,我们 4 所属树根结点,要遍历所可走路径。
如果我们只做一次还好,但是如果我们要重复寻找 4 的根节点,那是不是每次都要重复走一次,显得很浪费时间,所以,我们找到了一次 4 的根节点信息,直接用类似于备忘录的思想,把 4的父节点由3直接提升为1,这样子下次找就不用老是重复遍历了

代码如下:

int DisjointSets::findParentNode(int x){// 路径压缩改良版的查找// 如果 x的父节点是本身,说明x是根节点,退出循环,返回xwhile( x != this->parent[x] ){// 将 x 的父节点赋值为 x的父节点的父节点this->parent[x] = this->parent[this->parent[x]];// 改变此时x的值为 x的父节点x = this->parent[x];}return x;
}

下面可以来两道leetcode的题目练练手
547. 省份数量
839. 相似字符串组

两道题的代码答案分别是:

class Solution {public:const static int N = 205;int parent[N];int count = 0;// 查找 x 的根结点int find(int x){return x==parent[x]?x:find(parent[x]);}// 合并,把 y 合并到 x内void megre(int x,int y){int root1 = find(x);int root2 = find(y);// 判断 x与y 是否位于同一个并查集分量内,是就返回,不需要合并if(root1 == root2) return;// y的根结点的父亲更新为x的根结点parent[root2] = root1;// 合并成功说明少了一个点--count;}// 初始化并查集数据void init(int n){// 所有点的根结点初始默认是本身for(int i=0;i<n;++i)parent[i]=i;// 初始count大小就是ncount = n;}// 并查集的 第一题 实战int findCircleNum(vector<vector<int>>& isConnected) {int n = isConnected.size();// 初始化并查集init(n);for(int i = 0;i<n;++i){for(int j=0;j<n;++j){if(isConnected[i][j]==1){megre(i,j);}}}return count;}
};
class Solution {public:const static int N = 301;int parent[N];int count=0;/// 路径压缩int find(int x){while(x != parent[x]){parent[x] = parent[parent[x]];x = parent[x];}return x;}void union_set(int x,int y){int r1 = find(x);int r2 = find(y);if(r1==r2) return;parent[r2]=r1;--count;}void init(int n){count = n;for(int i=0;i<n;++i)parent[i]=i;}bool judge(string &s1,string &s2){int k = 0;for(int i=0;i<s1.size();++i)if(s1[i]!=s2[i])++k;if(k<=2) return true;else return false;}// 考查并查集int numSimilarGroups(vector<string>& strs) {int n = strs.size();init(n);for(int i=0;i<n;++i)for(int j=i+1;j<n;++j)if(judge(strs[i],strs[j]))union_set(i,j);return count;}
};

c++并查集(详细总结)相关推荐

  1. c++自带的可持久化平衡树?rope大法好!(超详细解答 + 5道例题讲解,可直接替代可持久化的线段树、并查集、平衡树!)

    整理的算法模板合集: ACM模板 目录 c++自带的可持久化平衡树?rope大法好! 1. 声明 2. 支持操作 char类型的rope int类型的rope 3. 具体的细节 4. "可持 ...

  2. POJ 1182 食物链 (并查集解法)(详细注释)

    食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 78510 Accepted: 23396 Description 动物王 ...

  3. 【POJ - 1182】 食物链(附超详细讲解)(并查集--种类并查集经典题)

    题干: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.  现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.  ...

  4. C++并查集算法(详细)

    C++并查集算法 什么是并查集? 并查集写法 详解 例题:洛谷 P3367.[模板]并查集 题意 代码 什么是并查集? 当我们在做图论题目的时候 经常会读到一些长这样的题目描述: -连接 a , b ...

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

    目录 1概论 2.树的表现形式 3.代码实现 3.1创立集合 3.2合并 3.3查询 3.4路径压缩 第一个方法:查找时优化 第二个方法:合并时优化(加权标记法) 4.完整代码 4.1优化前 4.2优 ...

  6. 精讲并查集经典习题:P1892 [BOI2003]团伙(超详细)

    一,需要开o2才能AC的代码 用emys[i]存储第i个人的敌人数,vector<long long>emyr[i]存储i个人的所以敌人,fa[i]存储第i个人的大boss. 1.初始化  ...

  7. 并查集/poj1182 noi2001食物链eat

    题意 有三类动物A,B,C,题中给出两种关系: 1 x y :x y 同类 2 x y :x吃y 对于假话的定义: 1.当前的话与前面的某些真的话冲突,就是假话: 2.当前的话中X或Y比N大,就是假话 ...

  8. poj1182(加权值的并查集)

    Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.  现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它 ...

  9. P1525关押罪犯(并查集补集)

    问题传送门 问题描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1-N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值&qu ...

最新文章

  1. Python全栈开发之路 【第六篇】:Python基础之常用模块
  2. 一次面试引发的思考(中小型网站优化思考) (转)
  3. 腾达fh307没有显示服务器名,腾达(Tenda)FH307路由器上网设置 | 192路由网
  4. html语言的字体设置
  5. 关于insert语句的插入问题
  6. Java中对象及常量,局部变量,全局变量的存储位置
  7. centos7搭建使用花生壳
  8. 为什么Word打印预览的跟实际的不一样呢
  9. 【Python】SVM分类 特征标准化+网格搜索最优模型参数+十折交叉验证
  10. python多行注释出错_python 有多行注释运行报错
  11. Harmony integration in Seurat V3 pipeline
  12. LaTex 如何生成参考文献
  13. android glide缺少方法,android - 无法膨胀且找不到类android支持设计的行为BottomSheetBehavior - 堆栈内存溢出...
  14. MathType找不到dll文件,原来要这样解决
  15. 2021年最新UI/UE设计软件全家桶
  16. GBase 8c 权限说明
  17. iPhone上实现流媒体播放器
  18. Scikit-learn学习系列 | 4. sklearn特征降维方法汇总(方差过滤,卡方,F过滤,互信息,嵌入法)
  19. augment()图像增强库
  20. IPD解读——从核心思想分析IPD体系

热门文章

  1. 亏损扩大盈利艰难,自动驾驶会是Uber的未来吗?
  2. java生成彩色二维码,附带中心logo
  3. 记录安装Cytoscape的过程
  4. 51单片机攻略—入门
  5. Android 跳转手机管家的自启动界面
  6. IE8浏览器32位被360篡改为64位(OCX控件在web页面不能加载的问题)
  7. java播放器_java音频播放器
  8. VS2012皮肤下载地址
  9. 浅谈功能游戏(严肃游戏)
  10. 第十一周项目3.2 警察和厨师 为Polic类和Cook类增加了对象成员,请扩充代码