数据结构——并查集 时间复杂度优化:启发式合并

5 篇文章 0 订阅
4 篇文章 0 订阅

观前提示:看这篇文章之前,需了解并查集基本使用

 并查集基础:并查集基础部分

了解之后,我们就进入启发式合并的讲解

启发式合并,顾名思义是去优化合并

在并查集基础中,我们合并是这样的:

void join(int x,int y){//join x和y
    if (find(x)==find(y)){
        return ;//在一个集合里,直接结束函数
    }else{
        f[b]=a;
    }
    return ;
}

那我们来设想一下:

假设此时A集合有10个人,B集合中有5个人:

A集合:

B集合:

         

A和a1是两个集合的祖先

那么假如说,f[a]=a1;

就变成了这样(并不太准确):

 

此时A的父节点变为了a1,b,c,d,e,f,g,h,i这些结点的父节点还都是A

所以当b,c,d,e,f,g,h,i寻找祖先的时候需要搜索A和a1两个点

寻找祖先节点的时间:

节点编号次数
b2
c2
d2
e2
f2
g2
h2
i2
b11
b21
c11
d11

一共要寻找20次(对于计算机来说小菜一碟,可还是要优化)

假设f[a1]=a呢?

那么就变成了这样:

 

并不美观

但是他的搜索次数比第一次会少,时间复杂度也跟着降低 

 

 

节点编号搜索次数
b1
c1
d1
e1
f1
g1
h1
i1
b12
b22
c12
d12

一共寻找16次,比上次少了

这只是一个较为简单的集合

当复杂起来   节省的时间就很多了

这就是启发式合并的思想:

        如果将a和b集合合并,如果a集合节点数比b集合节点数多,那么就执行f[b]=a;

        反之,就是f[a]=b;

剩下的就简单了

定义一个h数组,h[i]表示i的儿孙节点有多少,(仅限i是祖先节点,如果不是,h[i]为0)

那么初始化就要加上h的初始化:

void make(){
    for (int i=1;i<=n;i++){
        f[i]=i;
        h[i]=1;//初始化时,每个节点自己成为一个集合,所以h[i]为1
    }
}

join函数:

void join(){
    if (find(f[x])==find(f[y])){
        return ;
    }
    if (h[a]>h[b]){
        f[b]=a;
        h[a]+=h[b];
        h[b]=0;
    }else{
        f[a]=b;
        h[b]+=h[a];
        h[a]=0;
    }
}

总结:

        启发式合并思想很简单,能够降低时间复杂度(真香 ,所以大家在使用并查集的时候,建议把启发式合并带上

图表制作不易

点个赞再走吧

OrzOrz

 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值