并查集中的启发式合并

并查集通过启发式合并保持了树的形态,避免路径压缩带来的信息损失和暴力合并导致的超时问题。启发式合并总是将深度小的树合并到深度大的树上,保证树高O(logn),使得查找和查询路径均为O(logn)。文章提供了实现代码并结合BNUOJ 51275及FJUT1961题目解释了启发式合并的应用。

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

算法原理

并查集一般有两种方法来保持复杂度不退化,一种是路径压缩,另一种则是按照秩来做启发式合并。

一般情况下我们都是用第一种,压缩路径通过递推找到祖先节点后,在回溯时将它的子孙节点都直接指向祖先,这样以后每次调用Find( )函数找父亲时复杂度就变成了O(1)。但是路径压缩时直接将节点的父亲修改成最终的祖先节点,在破坏原先的树结构的同时,在有些题目中也会损失信息。而不使用压缩路径,直接用暴力并查集又容易超时。

所以我们考虑用启发式合并的方法来保持树的形态,那么如何控制并查集的复杂度呢?

因为并查集是一种树型结构,对于以每个节点为根节点的子树都有一个深度,如果把一棵深度大的树的根节点接在了一棵深度小的树上,因为是直接把根节点接在另一个的根节点上,所以整棵树的深度为那一棵深度大的树的深度加一。而如果把一棵深度小的树的根节点接在了一棵深度大的树上,可直接接上,不影响深度。如果两个数深度一样,则将接完后的树的深度加一即可。所以考虑每次都将深度小的树接在深度大的树上,这就是启发式合并的原理。虽然没有压缩路径,但是按秩合并可以保证树高是O(logn),这样找到树根是O(logn),路径查询也是O(logn)。

实现代码


int fu[maxn]//存放父节点
int deep[maxn];//记录深度

int findx(int x)//启发式合并不压缩路径,保持树结构
{
    if(fu[x] == x) return x;
    return findx(fu[x]);
}

void join(int x, int y,int k) //按照秩来做启发式合并
{
    int fx = findx(x);
    int fy = findx(y);
    if(fx==fy) return;
    if(deep[fx]>deep[fy])//深度小的树接在深度大的树上
        swap(fx,fy);
    fu[fx] = fy;
    if(deep[fx]==d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值