数据结构之并查集

并查集是什么

并查集是一种用来管理元素分组情况的数据结构。并查集可以高效地进行如下操作。不过需要注意并查集虽然可以进行合并操作,但是却无法进行分割操作。

  • 查询元素a和元素b是否属于同组。
  • 合并元素a和元素b所在的组。

并查集的简单案例

n个城市中(编号1~n),有一些城市间会有无向的通路。
现在小明想从a城市到b城市,判断是否能实现?即a和b是否有直接或间接的道路连通起来。
如有4个城市,其中1和2有道路,3和4有道路。
那么1 2可以相通,3 4可以相通,其他情况均不行。
简单的思考可以发现,如果我们把有通路的记为同一堆,只需判断a和b是否在同一堆里即可。
所以我们现在要实现的就是维护他们之间的连通关系。
为了查询的方便,我们用一堆里面的某一个城市当作这个堆的代表(老大),我们判断a和b即判断他们的老大是否相同。这个老大选择谁其实是无所谓的,我们一般用这个堆里面的第一个元素就当这个堆的老大。
现在我们来看看到底如果操作

并查集的应用

主要说明元素的查询合并

  • 查询
    顾名思义,这个操作就是查询某一个元素的老大是谁

查询之前我们需要把每一个pre[x]初始化,表示它自己就是他所在堆的老大

for(int i=1;i<=n;i++)
        pre[i]=i;

我们用pre[x]表示x的上级(不一定是老大)一直向上找,直到pre[x]=x就可以知道x就是x所在堆的老大

int findroot(int x)
{
    if(pre[x]==x)
        return x;
    else
        return findroot(pre[x]);
}

但这样有一个弊端,就是同一个x会被查询很多次,所以我们可以用一个小技巧,用pre[x]来记录它尽量上级的一个上级

int findroot(int x)
{
    if(pre[x]==x)
        return x;
    else
        return pre[x]=findroot(pre[x]);
}

这样我们就维护可以查询到x的老大是谁,如果有一条路把x和y连起来了,那么我们就需要把x和y所在的两个堆合并起来。

  • 合并
    如果我们需要合并a和b的对应的两个堆,我们只需要将其中一个堆的老大root2的上级改为另一个堆的老大root1,这样他们两个堆就通过root2联系起来了

其中的x和y分别是两个堆的root

void mix(int x,int y)
{
    pre[y]=x;
}

练习题目

牛客14685

/*
 * @Description: 
 * @Autor: Kadia
 * @Date: 2020-06-01 18:23:52
 * @LastEditors: Kadia
 * @connect: vx:ccz1354 qq:544692713
 * @LastEditTime: 2020-06-01 20:01:29
 * nk
 */ 

#include <bits/stdc++.h>

using namespace std;

int pre[100005];

int findroot(int x)
{
    if(pre[x]==x)
        return x;
    else
        return pre[x]=findroot(pre[x]);
}
void mix(int x,int y)
{
    pre[y]=x;
}
int main()
{
    int n,m;
    cin >> n >> m ;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    int x,y;
    int all=n;
    for(int i=1;i<=m;i++)
    {
        cin >> x >> y;
        int root1=findroot(x);
        int root2=findroot(y);
        if(root1!=root2)
        {
            mix(root1,root2);
            all--;
        }
    }
    cout << --all << endl ;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值