并查集讲解

本文详细介绍了并查集的基本概念及其实现方法,包括朴素做法和路径压缩做法。通过具体的代码示例展示了如何使用路径压缩来优化并查集的操作效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

周知,并查集学习过程中有朴素做法和路径压缩做法,之前一直不明白即使是朴素做法为什么会有形成一条很长的链的情况,而且讲解者一直不讲实例,只是画出一颗很长的链。
这里写图片描述
先把两种不同的模板放上:
朴素

    int find(int x)
    {
        if(x==fa[x]) return x;
        return find(fa[x]);
    }
    ... ...
    main:
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int u=find(x),v=find(y);
        if(u!=v)//合并
            fa[u]=v;
    }

路径压缩:

    int find(int x)
    {
        if(x==fa[x]) return x;
        return fa[x]=find(fa[x]);
    }
    ... ...
    main:
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int u=find(x),v=find(y);
        if(u!=v)//合并
            fa[u]=v;
    }

递归解释路径压缩:
这里写图片描述

下面代码样例:
5 4
4 5
3 4
2 3
1 2
在求find(x),x的父节点时,顺带将该路径上的点的父节点更新了,从而达到路径压缩。比如,下面代码中find(5)这一步,就可以使每个节点的father更新成1,
下次再find(4)时,if(x!=father[x])father[x]=find(father[x]);
那么4的父节点是1,下次递归就出来了。
而不用4->3->2->1这样寻找了。

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 20001
int father[maxn];
int m,n,i,x,y,q;
/*
  int find(int x)                  //用非递归的实现
  {
      while (father[x] != x) x= father[x];
      return x;
  }
  */
int find(int x)                  //用递归的实现
{
    if (father[x] != x) father[x] = find(father[x]);  //路径压缩
    return father[x];
}
void unionn(int r1,int r2)
{
    father[r2] = r1;
}
int main()
{
//    freopen("relation.in","r",stdin);
//    freopen("relation.out","w",stdout);
    cin >> n >> m;
    for (i = 1; i <= n; i++)
        father[i] = i;           //建立新的集合,其仅有的成员是i
    for (i = 1; i <= m; i++)
    {
        cin >> x >> y;
        int r1 = find(x);
        int r2 = find(y);
        if (r1 != r2) unionn(r1,r2);
    }  

//    cin >> q;
//    for (i = 1; i <= q; i++)
//    {
//        cin >> x >> y;
//        if (find(x) == find(y)) cout << "Yes" << endl;
//            else cout << "No" << endl;
//    }
    ***find(5);***
    for(int i=1;i<=n;i++)
        cout<<i<<","<<father[i]<<endl; 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值