c++初级并查集知识点总结

 更新时间:2019年07月08日 14:17:34   作者:Alex___Wei  
在本篇文章里小编给各位分享的是关于c++初级并查集知识点以及实例代码内容,有需要的朋友们学习下。

并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题。

有一个联合- 查找算法定义了两个用于此数据结构的操作:

  • Find :确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
  • Union:将两个子集合并成同一个集合。

并查集主要运用在合并元素以及查询两个元素是否在同一集合的问题,在信息学竞赛中广泛涉及

初始化:

一开始,每一个元素都是一个集合,打个比方,每个人所在的 " 家族 " 只有他一个人。我们还需要一个 f 数组,里面存的是他的 “父亲” 的编号,初始值为 f[1]=1,f[2]=2……f[n]=n,如图

2、find函数:find(a)是用来查找a的“祖先”的,例如,我们要查找 a 的祖先,就要去找 a 的父亲的父亲……,直到有个人 b ,他的父亲就是他自己,那么 b 就是 a 的祖先代码如下:int find (int x){    if(f[x] == x) return x;//如果x的父亲就是他自己,则x为a的祖先 else return find (f[x]);//否则a的祖先 就是a的父亲的祖先}int x=find(a);find函数:find(a)是用来查找a的“祖先”的,例如,我们要查找 a 的祖先,就要去找 a 的父亲的父亲……,直到有个人 b ,他的父亲就是他自己,那么 b 就是 a 的祖先代码如下:int find (int x){    if(f[x] == x) return x;//如果x的父亲就是他自己,则x为a的祖先 else return find (f[x]);//否则a的祖先 就是a的父亲的祖先}int x=find(a);

union函数:

union(a,b) 就是合并 a,b 这两个人所在的家族,只需要把 a的祖先的父亲 指向 b的祖先

如何合并?我们设 u=find(a),v=find(b) , 只要将 u,v 其中一个人的父亲编号指向另外一个人就行了,例如 f[u]=v

代码如下:

void Union (int a,int b)//因为union是c++的保留字,所以只好大写u

{

  int u= find(a), v= find(b);//寻找a,b的祖先

  f[u]=v;//合并家族

}

Union (a,b);

在合并的时候还有一个注意点:为什么不能直接把 a 的父亲指向 b ?因为这样并不能合并完全,a 的父亲, a 的父亲的父亲……,都不能合并到 b 的家族里(想一想,为什么?),如图

5、查询两个元素是否在同一集合里:查询 a,b 是否在同一集合里,就是看他们的祖先是否相等,若相等则在同一集合里,否则就不在代码如下:if( find(a) == find(b) ) cout<<"Y\n"; //如果祖先相等就输出“Y”else cout<<"N\n"; //否则输出“N”查询两个元素是否在同一集合里:查询 a,b 是否在同一集合里,就是看他们的祖先是否相等,若相等则在同一集合里,否则就不在代码如下:if( find(a) == find(b) ) cout<<"Y\n"; //如果祖先相等就输出“Y”else cout<<"N\n"; //否则输出“N”

例题:

 至此,你应该对并查集有了初步的了解,是时候上例题了

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入输出格式

输入格式:

第一行包含两个整数N、M,表示共有N个元素和M个操作。

接下来M行,每行包含三个整数Zi、Xi、Yi

当Zi=1时,将Xi与Yi所在的集合合并

当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N

输出格式:

如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N

其实,这道题目就是把上面几个步骤综合在一起,代码如下

并查集的路径压缩

路径压缩,顾名思义,就是将本来要很多步完成的事情压缩成一步

因为我们每次 find(a) 都要消耗 O (a 的层数 ) 的时间,如果数据构造成一条链,则每次 find 都需要 O(n) 的时间,这是我们不希望看到的

所以,我们可以把 f 数组的性质改变一下 f[a] 指向的编号变为 a 的祖先

代码该怎么写呢?我们只需要在 find 函数里把

return find (f[x]);

变成

return f[x]=find(f[x]);

就可以了

这样每一次 find 都会使路径上的每个 f[x] 指向 x 的祖先,每一次 find 也就只需要 1 步就行了(除非被合并过,那也只需要 2 步),这就是路径压缩的实质

相关文章

  • C/C++实现捕获所有信号的示例详解

    C/C++实现捕获所有信号的示例详解

    Linux的信号机制大部分情况下用不到,但是由于大部分信号的默认处理是终止进程,不正确处理会惹麻烦,所以我们来看看如何使用C/C++实现捕获所有信号吧
    2024-03-03
  • OPENMP SECTIONS CONSTRUCT原理示例解析

    OPENMP SECTIONS CONSTRUCT原理示例解析

    这篇文章主要为大家介绍了OPENMP SECTIONS CONSTRUCT原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • C++ string 字符串查找匹配实例代码

    C++ string 字符串查找匹配实例代码

    下面小编就为大家带来一篇C++ string 字符串查找匹配实例代码。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • 浅谈Qt实现HTTP的Get/Post请求

    浅谈Qt实现HTTP的Get/Post请求

    本文主要介绍了浅谈Qt实现HTTP的Get/Post请求,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • C++利用map实现并查集

    C++利用map实现并查集

    这篇文章主要为大家详细介绍了C++利用map实现并查集,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C语言编程基础char类型转换示例

    C语言编程基础char类型转换示例

    这篇文章主要为大家介绍了C语言编程基础char类型转换示例代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • C语言中isalnum()函数和isalpha()函数的对比使用

    C语言中isalnum()函数和isalpha()函数的对比使用

    这篇文章主要介绍了C语言中isalnum()函数和isalpha()函数的对比使用,都可以判断是否为字母但isalnum的判断还包括数字,需要的朋友可以参考下
    2015-08-08
  • c++快速排序详解

    c++快速排序详解

    快速排序总体思想:先找到一个枢轴,让他作为分水岭,通过一趟排序将待排序的记录分割成两部分,前面一部分都比枢轴小,后面一部分枢轴大,然后又分别对这两部分记录继续进行递归的排序,达到整个序列有序的目的
    2017-05-05
  • c++中strcpy函数在VS2015无法使用的问题

    c++中strcpy函数在VS2015无法使用的问题

    这篇文章主要介绍了c++中strcpy函数在VS2015无法使用的问题,具有一定的参考价值,有需要的可以了解一下。
    2016-11-11
  • C语言简单实现银行ATM存取款功能

    C语言简单实现银行ATM存取款功能

    这个是大一时期写的。大四的时候整理了一下(本人C语言学的也不太好)。肯定很多不足和存在漏洞的地方、仅供借鉴、仅供借鉴,代码中有大量注释,新手看起来也没有困难
    2021-11-11

最新评论