iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C/C++并查集的查询与合并实现原理
  • 741
分享到

C/C++并查集的查询与合并实现原理

C++并查集的查询与合并C语言并查集的合并与查询 2023-02-13 12:02:06 741人浏览 独家记忆
摘要

目录一、并查集的概念二、并查集的实现1.并查集不同集合(树)的形成2.find()函数找一个元素集合的编号3.合并两个不同集合(合并两棵不同的树)4.查询两个元素是否在一个集合5.并

标题:并查集的查询与合并详解 作者:@Ggggggtm 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景

一、并查集的概念

并查集是一种树形的数据结构。使用树型结构来存储数据。树根的编号即为整个树的标号,且每个节点存储的数据是他的父节点下标。

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

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

二、并查集的实现

1.并查集不同集合(树)的形成

我们把并查集不同集合(树)的实现主要分为以下几个点:

  • 我们先给出n个数据,把n个数据存储到不同的集合当中(p[ i ] = i),在这里我们把每个p[ i ]分别看成一个不同集合(也就是一棵树)。
  • p[ i ] = i,i即为这棵树的编号,这颗树下面的孩子节点存储的数据是父节点的下标。
  • 当p[ i]=i 时,就相当于找到了根节点。
  • 我们刚开始每个集合中的元素只有一个。后续合并后,集合元素个数不断增加。

2.find()函数找一个元素集合的编号

(元素所属于树的祖宗)

我们查找一个元素的集合,把元素的当作下标传给find()函数,代码如下:

int find(int x)
{
    if(p[x]!=x)
    {
        p[x]=find(p[x]);
    }
    return p[x];
}

我们p[x]中存储的正是他的父节点,从而就可以一直往上查找,直到p[ x ]=x时结束。当p[ x ]=x时,就相当于找到了根节点。此时的p[ x ]存储的是这棵树的编号。我这发现,刚开始每个集合当中都只有一个元素,也就是p[ x ],后面我们会对不同的集合进行合并,使得一个集合有多个元素。

我们再找祖宗节点时进行了路径压缩。什么是路径压缩呢?路径压缩就是我们在查找某个元素的祖宗时,在找父节点的这条路经上的元素都指向祖宗节点,以便于我们后面的查找的时间复杂度近乎O(1)。

3.合并两个不同集合(合并两棵不同的树)

我们直到了每棵树的根节点存储的是这个树的编号,而不是父节点。当我们要合并两颗树时,我们只需要把一棵树的根节点存储的编号改为另一棵树的根节点编号。简单的理解就是一个树的根节不再是根节点,而是一个子节点,该树的根节点存储的也不再是编号,而是存储的父节点,该父节点就是另一棵树的根节点。我们看代码:

//合并  把a的祖宗节点的父节点当作b的祖宗结点
p[find(a)]=find(b);

4.查询两个元素是否在一个集合

我们有了find()函数,就可以很简单的判断出两个元素的是否在同一个集合当中(两个元素是否在同一个树中)。我们只需要判断两个元素集合的编号是否相同(两个元素的祖宗节点是否相同)即可。我们看代码:

//看a、b两个元素是否在同一个集合当中
if(find(a)==find(b))
    cout<<"Yes"<<endl;
else
    cout<<"No"<<endl;

5.并查集例题训练1

一共有 n 个数,编号是1∼n,最开始每个数各自在一个集合中。

现在要进行m个操作,操作共有两种:

  • M a b,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  • Q a b,询问编号为a和b的两个数是否在同一个集合中;

输入格式:

第一行输入整数n和m。

接下来m行,每行包含一个操作指令,指令为M a bQ a b中的一种。

输出格式:

对于每个询问指令Q a b,都要输出一个结果,如果a和b在同一集合内,则输出Yes,否则输出No

每个结果占一行。

数据范围:

1≤n,m≤10e5 1≤n,m≤10e5

输入样例:

4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4

输出样例:

Yes
No
Yes

答案如下:

#include<iOStream>
using namespace std;
const int N=100010;
int p[N];
//找祖宗+路径压缩
int find(int x)
{
    if(p[x]!=x)
    {
        p[x]=find(p[x]);
    }
    return p[x];
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        p[i]=i;
    while(m--)
    {
        char op[2];
        int a,b;
        cin>>op>>a>>b;
        if(op[0]=='M')
        {
            //合并  把a的祖宗节点的父节点当作b的祖宗结点
            p[find(a)]=find(b);
        }
        else
        {
            if(find(a)==find(b))
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
        }
    }
    return 0;
}

6.并查集例题训练2

给定一个包含nn个点(编号为1∼n1∼n)的无向图,初始时图中没有边。

现在要进行mm个操作,操作共有三种:

  • C a b,在点aa和点bb之间连一条边,aa和bb可能相等;
  • Q1 a b,询问点aa和点bb是否在同一个连通块中,aa和bb可能相等;
  • Q2 a,询问点aa所在连通块中点的数量;

输入格式

第一行输入整数nn和mm。

接下来mm行,每行包含一个操作指令,指令为C a bQ1 a bQ2 a中的一种。

输出格式

对于每个询问指令Q1 a b,如果aa和bb在同一个连通块中,则输出Yes,否则输出No

对于每个询问指令Q2 a,输出一个整数表示点aa所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤1051≤n,m≤105

输入样例:

5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5

输出样例:

Yes
2
3

我们这个题相对于上个题就是对出了一个统计一个集合元素的个数。整体思路大同小异,我们直接看代码解析:

#include<iostream>
using namespace std;
const int N=100010;
int p[N],cnt[N];
int find(int x)
{
    if(p[x]!=x)
    {
        p[x]=find(p[x]);
    }
    return p[x];
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        p[i]=i;
        cnt[i]=1;
    }
    while(m--)
    {
        char op[5];
        int a,b;
        scanf("%s",op);
        if(op[0]=='C')
        {
            scanf("%d%d",&a,&b);
            if(find(a)==find(b))
                continue;
            cnt[find(b)]+=cnt[find(a)];
            p[find(a)]=find(b);
        }
        else if(op[1]=='1')
        {
            scanf("%d%d",&a,&b);
            if(find(a)==find(b))
                printf("Yes\n");
            else
                printf("No\n");
        }
        else
        {
            scanf("%d",&a);
            printf("%d\n",cnt[find(a)]);
        }
    }
    return 0;
}

注意,我们刚开始每个集合中的元素只有一个。后续合并后,集合元素个数不断增加。

三、总结

我们主要掌握find()函数,并查集算法中,最为核心的就是find()函数。在这个算法中,路径压缩给我们的算法效率提高了很多,这个也是需要理解的。合并、查询是并查集的两个主要操作,我们也应该熟悉理解。

到此这篇关于C/C++并查集的查询与合并实现原理的文章就介绍到这了,更多相关c++并查集内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C/C++并查集的查询与合并实现原理

本文链接: https://www.lsjlt.com/news/195759.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C/C++并查集的查询与合并实现原理
    目录一、并查集的概念二、并查集的实现1.并查集不同集合(树)的形成2.find()函数找一个元素集合的编号3.合并两个不同集合(合并两棵不同的树)4.查询两个元素是否在一个集合5.并...
    99+
    2023-02-13
    C++并查集的查询与合并 C语言并查集的合并与查询
  • SQLSERVER实现连接与合并查询
    创建测试表MyStudentInfo CREATE table MyStudentInfo ( Id int not null primary key, Name varcha...
    99+
    2024-04-02
  • C++如何实现并查集算法
    这篇文章主要介绍了C++如何实现并查集算法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、并查集的初始化并查集是用一个数组实现的。首先先定义一个数组:int fa...
    99+
    2023-06-29
  • Java 并发集合背后的原理与实现
    并发集合概述 在多线程编程中,多个线程可能同时访问和修改共享数据,这可能导致数据不一致或程序崩溃。为了解决这个问题,Java 提供了并发集合类,这些集合类实现了线程安全,可以确保在多线程环境下对数据的并发访问和修改是安全的。 CopyOn...
    99+
    2024-02-07
    Java 集合 并发集合 线程安全 CopyOnWriteArrayList ConcurrentHashMap ConcurrentLinkedQueue
  • SQL SERVER如何实现连接与合并查询
    这篇文章主要介绍了SQL SERVER如何实现连接与合并查询,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。创建测试表MyStudentInfoCREATE ...
    99+
    2023-06-29
  • C++并查集常用操作
    并查集 是一种树型的数据结构,用于处理一些不相加集合的合并和查询问题。在使用中常常以森林来表示。 并查集也是用来维护集合的,和前面学习的set不同之处在于,并查集能很方便地同时维护很...
    99+
    2024-04-02
  • C语言并查集的非递归实现详解
    目录【算法分析】【算法代码】并查集压缩路径非递归写法参考文章总结【算法分析】 经典的递归实现的并查集,在数据规模过大时,可能会爆栈,因此有了并查集的非递归实现。核心代码如下: i...
    99+
    2024-04-02
  • C++并查集算法简单详解
    目录1、并查集的初始化2、并查集的查找操作3、并查集的合并操作4、为什么要路径压缩?5、实现路径压缩总结1、并查集的初始化 并查集是用一个数组实现的。首先先定义一个数组: int f...
    99+
    2024-04-02
  • C#集合之并发集合的用法
    .NET 4 开始,在System.Collection.Concurrent中提供了几个线程安全的集合类。线程安全的集合可防止多个线程以相互冲突的方式访问集合。为了对集合进行线程安...
    99+
    2024-04-02
  • Java如何实现并查集
    这篇文章主要介绍“Java如何实现并查集”,在日常操作中,相信很多人在Java如何实现并查集问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java如何实现并查集”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-25
  • c++与python实现二分查找的原理及实现
    目录1、时间复杂度与优缺点2、python实现3、C++实现在计算机中,数据的查找方式与其存储方式关系密切。试想一下,如果图书馆中书籍杂乱无章的存放,那么要想找到心仪的书籍将会非常困...
    99+
    2024-04-02
  • C++高级数据结构之并查集
    目录1.动态连通性2.union-find算法API3.quick-find算法4.quick-union算法5.加权quick-union算法6.使用...
    99+
    2024-04-02
  • C++并查集有哪些常用操作
    本篇内容介绍了“C++并查集有哪些常用操作”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!并查集 是一种树型的数据结构,用于处理一些不相加集合...
    99+
    2023-06-20
  • C#并查集(union-find)算法详解
    目录算法的主题思想:1. 动态连通性2. 定义问题3. quick-find算法实现算法分析4. quick-union算法实现森林表示算法分析5.加权 quick-uni...
    99+
    2024-04-02
  • 【MySQL系列】MySQL复合查询的学习 _ 多表查询 | 自连接 | 子查询 | 合并查询
    「前言」文章内容大致是对MySQL复合查询的学习。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、基本查询回顾二、多表查询三、自连接四、子查询4.1 单行子查询4.2 多行子查询4....
    99+
    2023-08-30
    mysql 学习 android
  • MySQL查询数据之合并查询结果的案例
    小编给大家分享一下MySQL查询数据之合并查询结果的案例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!.利用union...
    99+
    2024-04-02
  • C#中的并发集合Concurrent类
    一、概述: System.Collections.Concurrent 命名空间提供多个线程安全集合类。 当有多个线程并发访问集合时,应使用这些类代替 System.Col...
    99+
    2024-04-02
  • C#中怎么实现多个集合的交集查找
    在C#中,可以使用LINQ来实现多个集合的交集查找。首先,将多个集合合并到一个集合中,然后使用LINQ的Intersect方法来查找...
    99+
    2024-04-02
  • sql如何查询两个表的并集
    SQL查询两个表的并集可以使用UNION操作符实现。UNION操作符用于合并两个或多个SELECT语句的结果...
    99+
    2023-09-15
    sql
  • mysql如何实现查询并排序
    本篇内容主要讲解“mysql如何实现查询并排序”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mysql如何实现查询并排序”吧! 在m...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作