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

 更新时间:2022年02月14日 10:15:37   作者:Curz酥  
大家好,本篇文章主要讲的是C++并查集算法简单详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

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++并查集算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C/C++语言中结构体的内存分配小例子

    C/C++语言中结构体的内存分配小例子

    当未用 #pragma 指令指定编译器的对齐位数时,结构体按最长宽度的数据成员的宽度对齐;当使用了 #pragma 指令指定编译器的对齐位数时,结构体按最长宽度的数据成员的宽度和 #pragma 指令指定的位数中的较小值对齐
    2013-10-10
  • C/C++实现数字与字符串互相转换的多种方法

    C/C++实现数字与字符串互相转换的多种方法

    在C/C++程序中,会需要把数字与字符串做出互相转换的操作,用于实现程序想要的效果,下面将介绍多种方法实现数字与字符串互相转换,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-08-08
  • C++中的std::nothrow使用

    C++中的std::nothrow使用

    这篇文章主要介绍了C++中的std::nothrow使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C语言位段(位域)机制结构体的特殊实现及解析

    C语言位段(位域)机制结构体的特殊实现及解析

    这篇文章主要为大家介绍了C语言位段位域机制结构体的特殊实现讲解有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-02-02
  • C++之编写高效Makefile文件最佳方法

    C++之编写高效Makefile文件最佳方法

    在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署,然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高开发效率和产品质量,需要的朋友可以参考下
    2023-05-05
  • c语言打印输出双引号的方法示例

    c语言打印输出双引号的方法示例

    这篇文章主要介绍了c语言打印输出双引号的方法,大家参考使用吧
    2013-11-11
  • C语言代码实现简单扫雷小游戏

    C语言代码实现简单扫雷小游戏

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • C++ STL 序列式容器与配接器的简单使用

    C++ STL 序列式容器与配接器的简单使用

    本文主要介绍了C++ STL 序列式容器与配接器的简单使用,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • C++二分查找算法实例

    C++二分查找算法实例

    这篇文章主要为大家详细介绍了C++二分查找算法的实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • C++ const和指针详情

    C++ const和指针详情

    这篇文章主要介绍了C++ const和指针,关于使用const来修饰指针,有两种不同的方式。第一种是让指针指向一个常量对象,这样可以防止使用该指针进行修改指向的值。第二种则是将指针本身声明为常量,可以防止改变指针指向的位置,下面来看看文章的详细内容
    2021-11-11

最新评论