C++并查集算法简单详解

目录
  • 1、并查集的初始化
  • 2、并查集的查找操作
  • 3、并查集的合并操作
  • 4、为什么要路径压缩?
  • 5、实现路径压缩
  • 总结

1、并查集的初始化

并查集是用一个数组实现的。首先先定义一个数组:

int father[N];

father[i]表示元素i的父亲结点。

接下来进行初始化。一开始,每个元素都分别是独立的一个集合,父亲结点就是它自己,所以初始化时将所有father[i]等于i:

for(int i = 1; i <= N; i++){
    father[i] = i;
}

这样,就将father数组初始化完毕。

2、并查集的查找操作

由于规定同一个集合中只存在一个根结点,因此查找操作,就是查找给定结点的根结点的过程。可以通过递推或递归来实现,思路都是一样的,都是反复寻找父亲结点,直到找到根结点为止。

递推代码:

//findFather函数返回元素x所在集合的根结点
int findFather(int x){
    while(x != father[x]){    //如果不是根结点,继续循环
        x = father[x];    //获得自己的父亲结点
    }
    return x;
}

上述代码中, while(x != father[x]),说明当x的父亲结点不等于本身时,也就是x不是根结点时就继续循环,因为父亲结点等于本身这个情况,只有在根结点才会出现。

递归代码:

int findFather(int x){
    if(x == father[x]) return x;    //如找到根结点,就返回根结点编号x
    else return findFather(father[x]); //否则,递归判断x的父亲结点是否是根结点
}

3、并查集的合并操作

合并,就是把两个集合合并成一个集合。实现过程是:先判断两个元素是否属于同一个集合,不属于同一个集合,就开始进行合并操作。判断两个元素是否属于同一个集合的具体思路,就是调用上面的findFather函数,分别查找两个元素所属集合的根结点,根结点不同,则两个元素不属于同一个集合。合并两个集合的具体思路,就是将其中一个集合的根结点的父亲指向另外一个集合的根结点即可。

合并操作的代码实现:(假设有两个集合,一个集合里有元素a,一个集合有元素b)

void Union(int a, int b){
    //让一个集合的根结点的父亲指向另一个集合的根结点
    father(findFather(a)) = findFather(b);
}

注意,合并操作之前,最好先判断下待合并的两个元素是否位于同一个集合。

4、为什么要路径压缩?

5、实现路径压缩

由于findFather函数目的就是查找根结点,所以,我们在查找结点的路径上直接将所有结点的父亲都指向根结点,查找的时候就不必一直回溯去寻找父亲了,查询的复杂度可以降为O(1)。

比如下面这张图:

观察图不难发现,上图中father[1] = 1,father[2] = 1,father[3] = 2,father[4] = 3。经过路径压缩,就变成下面这幅图:

相当于将所有结点的父亲都直接指向根结点,这就是路径压缩。

如何用代码实现路径压缩呢?以下是具体代码:

int findFather(int x){
    if(father[x] != x) father[x] = findFather(father[x]);
    return father[x];
}

以上代码,实现了在查询获取根结点的同时,将路径进行压缩优化,代码虽然很短,但是很巧妙,下面解释下上述代码:

 if(father[x] != x),当所查找的元素x的父亲结点不是自己,也就是x不是根结点时,

findFather(father[x]),就继续递归查找父结点,直到找到根结点为止,

father[x] = findFather(father[x]),然后将找到的根结点直接赋给x的父亲结点。

这样就实现了路径压缩,即将结点的父亲直接指向根结点。

return father[x],返回查找到的根结点。

总结

到此这篇关于C++并查集算法简单详解的文章就介绍到这了,更多相关C++并查集算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现并查集

    本文实例为大家分享了C++实现并查集的具体代码,供大家参考,具体内容如下 #include <iostream> #include <vector> #include <cassert> using namespace std; class UnionFind{ private: vector<int> parent; int count; //优化,记录p和q所在组的深度,在合并时将深度小的结点的根指向深度大的结点的根 vector<int>

  • C++并查集亲戚(Relations)算法实例

    本文实例讲述了C++并查集亲戚(Relations)算法.分享给大家供大家参考.具体分析如下: 题目: 亲戚(Relations) 或许你并不知道,你的某个朋友是你的亲戚.他可能是你的曾祖父的外公的女婿的外甥的表姐的孙子.如果能得到完整的家谱,判断两个人是否亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及.在这种情况下,最好的帮手就是计算机. 为了将问题简化,你将得到一些亲戚关系的信息,如同Marry和Tom是亲戚,Tom和B en是

  • c++并查集优化(基于size和rank)

    基于size的优化是指:当我们在指定由谁连接谁的时候,size数组维护的是当前集合中元素的个数,让数据少的指向数据多的集合中 基于rank的优化是指:当我们在指定由谁连接谁的时候,rank数组维护的是当前集合中树的高度,让高度低的集合指向高度高的集合 运行时间是差不多的: 基于size的代码: UnionFind3.h #ifndef UNION_FIND3_H_ #define UNION_FIND3_H_ #include<iostream> #include<cassert>

  • C++并查集常用操作

    并查集 是一种树型的数据结构,用于处理一些不相加集合的合并和查询问题.在使用中常常以森林来表示. 并查集也是用来维护集合的,和前面学习的set不同之处在于,并查集能很方便地同时维护很多集合.如果用set来维护会非常的麻烦.并查集的核心思想是记录每个结点的父亲结点是哪个结点. 前言 并查集是一种多叉树,用于处理不相交的集合的合并与查询问题(判断). 通俗理解:在日常生活中,我们会因为某个人是自己的朋友,哪怕是朋友的朋友也是有朋友,会给予通融. 偏袒.而并查集的基本概念,就是判断某两个集合是否是"朋

  • C++并查集算法简单详解

    目录 1.并查集的初始化 2.并查集的查找操作 3.并查集的合并操作 4.为什么要路径压缩? 5.实现路径压缩 总结 1.并查集的初始化 并查集是用一个数组实现的.首先先定义一个数组: int father[N]; father[i]表示元素i的父亲结点. 接下来进行初始化.一开始,每个元素都分别是独立的一个集合,父亲结点就是它自己,所以初始化时将所有father[i]等于i: for(int i = 1; i <= N; i++){ father[i] = i; } 这样,就将father数组

  • redis集群规范详解

    本文档翻译自 http://redis.io/topics/cluster-spec . 引言 这个文档是正在开发中的 Redis 集群功能的规范(specification)文档, 文档分为两个部分: 第一部分介绍目前已经在 unstable 分支中实现了的那些功能. 第二部分介绍目前仍未实现的那些功能. 文档各个部分的内容可能会随着集群功能的设计修改而发生改变, 其中, 未实现功能发生修改的几率比已实现功能发生修改的几率要高. 这个规范包含了编写客户端库(client library)所需的

  • Python深度强化学习之DQN算法原理详解

    目录 1 DQN算法简介 2 DQN算法原理 2.1 经验回放 2.2 目标网络 3 DQN算法伪代码 DQN算法是DeepMind团队提出的一种深度强化学习算法,在许多电动游戏中达到人类玩家甚至超越人类玩家的水准,本文就带领大家了解一下这个算法,论文的链接见下方. 论文:Human-level control through deep reinforcement learning | Nature 代码:后续会将代码上传到Github上... 1 DQN算法简介 Q-learning算法采用一

  • Python 十大经典排序算法实现详解

    目录 关于时间复杂度 关于稳定性 名词解释 1.冒泡排序 (1)算法步骤 (2)动图演示 (3)Python代码 2.选择排序 (1)算法步骤 (2)动图演示 (3)Python代码 3.插入排序 (1)算法步骤 (2)动图演示 (3)Python代码 4.希尔排序 (1)算法步骤 (2)Python代码 5.归并排序 (1)算法步骤 (2)动图演示 (3)Python代码 6.快速排序 (1)算法步骤 (2)动图演示 (3)Python代码 7.堆排序 (1)算法步骤 (2)动图演示 (3)P

  • java 中模式匹配算法-KMP算法实例详解

    java 中模式匹配算法-KMP算法实例详解 朴素模式匹配算法的最大问题就是太低效了.于是三位前辈发表了一种KMP算法,其中三个字母分别是这三个人名的首字母大写. 简单的说,KMP算法的对于主串的当前位置不回溯.也就是说,如果主串某次比较时,当前下标为i,i之前的字符和子串对应的字符匹配,那么不要再像朴素算法那样将主串的下标回溯,比如主串为"abcababcabcabcabcabc",子串为"abcabx".第一次匹配的时候,主串1,2,3,4,5字符都和子串相应的

  • JavaScript算法系列之快速排序(Quicksort)算法实例详解

    "快速排序"的思想很简单,整个排序过程只需要三步: (1)在数据集之中,选择一个元素作为"基准"(pivot). (2)所有小于"基准"的元素,都移到"基准"的左边:所有大于"基准"的元素,都移到"基准"的右边. (3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止. 举例来说,现在有一个数据集{85, 24, 63, 45,

  • Java版超大整数阶乘算法代码详解-10,0000级

    当计算超过20以上的阶乘时,阶乘的结果值往往会很大.一个很小的数字的阶乘结果就可能超过目前个人计算机的整数范围.如果需求很大的阶乘,比如1000以上完全无法用简单的递归方式去解决.在网上我看到很多用C.C++和C#写的一些关于大整数阶乘的算法,其中不乏经典但也有很多粗糙的文章.数组越界,一眼就可以看出程序本身无法运行.转载他人文章的时候,代码倒是仔细看看啊.唉,粗糙.过年了,在家闲来蛋疼,仔细分析分析,用Java实现了一个程序计算超大整数阶乘.思想取自网上,由我个人优化和改进. 这个方法采用"数

  • KnockoutJS数组比较算法实例详解

    这篇文章主要介绍了KnockoutJS数组比较算法实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前端开发中,数组是一种非常有用的数据结构.这篇博客会解释并分析KnockoutJS实现中使用的数据比较算法. 算法的目的 KnockoutJS使用MVVM的思想,view model中的数组元素会对应data model中的数组数据,当用户进行输入或者请求后台时,数组数据会发生变更, 从而带动UI的更新.例如购物车类的页面,用户可以通过点击

  • Python猜数字算法题详解

    今天刷的第一道算法题,先拿一道简单点的试试手,这道题目的要求是: 两个人甲乙在猜数字,甲先从1,2,3三个数字中随机抽3次,结果是guess.乙随后也随机抽三次,结果是answer.然后对比甲乙两个人的结果.示例如下: guess:[1,2,3], answer: [1, 2, 3] 那么结果就是猜对了3次 guess: [1,2,3] answer:[3,2,1] 那么结果就是猜对了1次 guess: [1,2,3], answer:[3, 3,1] 那么结果就是猜对了0次 即将guess和a

  • python连接mongodb集群方法详解

    简单的测试用例 #!/usr/bin/python # -*- coding: UTF-8 -*- import time from pymongo import MongoClient # 连接单机 # single mongo # c = MongoClient(host="192.168.89.151", port=27017) # 连接集群 c = MongoClient('mongodb://192.168.89.151,192.168.89.152,192.168.89.1

随机推荐