并查集的路径压缩和按秩合并

记录一下并查集的两种优化:

路径压缩

路径压缩是并查集最常用的一个优化之一,他可以优化查询的速度。我们发现,在普通的并查集中,如果我们要询问一个元素所属哪个集合,我们只关心集合的代表是谁(也就是并查集树形结构中的树根是谁),而并不关心树的形态。那么我们可以在每次执行往上找根节点的时候,把路径上所有的元素的父亲全部指向树根(也就是通过改变树结构,降低了树的高度,增快了我们的查询速度),这样的均摊复杂度为 O(logN) O ( l o g N )
这里写图片描述

路径压缩后的查询函数

int findfa(int x)
{
    if(fa[x]==x) return fa[x];
    else return fa[x]=findfa(fa[x]);//fa[x]=findfa(fa[x])路径压缩
}

按秩合并

按秩合并是一种启发式合并,主要思想是合并的时候把小的树合并到大的树以减少工作量。
我们先来定义一下并查集的“秩”,有两种定义的方法:
1、树的高度
2、树的节点数
我们在路径压缩之后一般采用第二种,因为第一种在路径压缩之后就已经失去意义了,按照第二种合并可以减少一定的路径压缩的工作量。(但其实也不会太多,所以一般来说路径压缩就够用了)
单独采用按秩合并的话平摊查询时间复杂度同样为 O(logN) O ( l o g N )
如果我们把路径压缩和按秩合并合起来一起使用的话可以把查询复杂度下降到 O(α(n)) O ( α ( n ) ) ,其中 α(n) α ( n ) 为反阿克曼函数。阿克曼函数是一个增长极其迅速的函数,而相对的反阿克曼函数是一个增长极其缓慢的函数,所以我们在算时间复杂度的时候可以把他视作一个常数看待。

按树高为秩

void merge(int x,int y)
{
    int fx=findfa(x),fy=findfa(y);
    if(rank[fx]>rank[fy]) fa[fy]=fx;
    else
    {
        fa[fx]=fy;
        if(rank[fx]==rank[fy]) rank[fy]++;
//解释一下这儿,只有两颗树的高度相等的时候合并后高度才会增加
//因为你合并是把小的直接接到根节点上,深度只会+1,如果深度+1都没超过大的那肯定合并后的树高度不会增加
    }
}

按节点数为秩

void merge(int x,int y)
{
    int fx=findfa(x),fy=findfa(y);
    if(fx==fy)
        return;
    if(size[fx]>size[fy])
        swap(fx,fy);
    fa[fx]=fy;
    size[fy]+=size[fx];
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值