并查集的介绍与应用

定义

并查集是一种维护集合的数据结构,并-Union,查-Find ,集-Set。即支持合并和查找两种操作。
注:同一个集合只存在一个根结点

int father[N];//数组实现
father[i]=j;//表示元素i的父亲结点是j
father[i]=i;//表示元素i的父亲结点是i,即i是集合的根结点
//则i与j组成了一个以根结点为i的集合

基本操作

1.初始化

 //初始化
    for(int i=0;i<n;i++)
    father[i]=i;

2.查找根结点

//递推实现-通过循环实现
int findFather1(int n){
    //当father[n]=n时,n才为根结点
    while(n!=father[n])
    n=father[n];
    return n;
}
//递归实现-通过不断调用自身实现
int findFather2(int n){
    if(n==father[n]) return n;
    else {
        n=father[n];
        return findFather2(n);//即return findFather2(father[n]);
    }
}

3.合并

//将两个数的不同集合合并成一个集合
void merge(int a,int b){
    int fa=findFather1(a);
    int fb=findFather1(b);
    if(fa!=fb)
    father[fb]=fa;//为这两个集合建立联系,使之变成同一集合
}

4.路径压缩

由于上面所建立的并查集特别长,每次找根结点时均要从最底下回溯,效率非常低,于是考虑将所有结点均变成根结点的直接分支,此时高度就变成了1。

//递推实现
int findFather1(int n){
    int a=n;
    while(n!=father[n])
    n=father[n];//找根结点,n为根结点
    while(a!=father[a]){
        int x=a;
        a=father[a];//不断回溯
        father[x]=n;//改新父亲为根结点
    }
    return n;
}
//递归实现
int findFather2(int n){
    //找根结点,n为根结点
    if(n==father[n]) return n;
    else{
        int N=findFather2(father[n]);//回溯
        father[n]=N;//改新父亲为根结点
        return N;
    }
}

应用

在这里插入图片描述
思路:将不同组好朋友看成不同集合,分组就是集合合并的过程。
1.合并:边输入同时边合并即可实现。
2.计数:对于计算组数,我们可以设置一个hash数列,以根结点为下标-key,值为布尔型,最后累加即可得到结果。

#include <iostream>
using namespace std;
const int maxn=100;
int father[maxn];
bool isfather[maxn]={false};//标记是否为根结点

void initial(int n){
    for(int i=0;i<n;i++)
    father[i]=i;
}
int findFather(int x){
    int a=x;
    //找根结点
    while(x!=father[x])
    x=father[x];
    //压缩路径
    while(a!=father[a]){
        int b=a;
        a=father[a];
        father[b]=x;
    }
    return x;
}
void Union(int a,int b){
    int fa=findFather(a);
    int fb=findFather(b);
    if(fa!=fb)
    father[fb]=fa;
}
int main(){
    int num,group,sum=0;
    int a,b;//装元素
    cin>>num>>group;
    initial(num);//初始化
    for(int i=0;i<group;i++){
        cin>>a>>b;
        Union(a,b);//合并
    }
    for(int i=1;i<=num;i++){
        isfather[findFather(i)]=true;//改根结点为true;
    }
    //计算根结点数,即合并后组数
    for(int i=1;i<=num;i++){
        sum+=isfather[i];//bool型转换为整型:false->0;true->1;
    }
    cout<<sum<<endl;
    return 0;
}
  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值