并查集的两个优化(秩优化+路径压缩)

路径压缩

寻找祖先时采用递归,但是一旦元素一多起来,或退化成一条链,每次GetFather都将会使用O(n)的复杂度,这显然不是我们想要的。对此,我们必须要进行路径压缩,即我们找到最久远的祖先时“顺便”把它的子孙直接连接到它上面。这就是路径压缩了。使用路径压缩的代码如下,时间复杂度基
本可以认为是常数的。

路径压缩可以采用迭代和递归方式递归方式实现简单但是有些题目会爆栈的。
//递归形式的路径压缩
int getf(int v)
{
    if(v==f[v]) return v;
    return f[v]=getf(f[v]);
}

//迭代形式的路径压缩
int getf(int v) {
    int p = v, t;
    while (f[p] != p) p = f[p];//找到祖先p
    while (v != p) { t = f[x]; f[x] = p; x = t; } //路径压缩
    return v;
}

按秩合并

这里也可以应用一个简单的启发式策略——按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。为了保存秩,需要额外使用一个与 uset 同长度的数组,并将所有元素都初始化为 0。这样找祖先会减少递归迭代的次数,最坏只有logN次。
void Merge(int x,int y)
{
    int t1=getf(x),t2=getf(y);
    if(t1==t2) return ;//已合并返回
    if(rnk[t1]>rnk[t2]) f[t2]=t1;  //把y的祖先t2和并到x的祖先t1上。因以t1为根的树更高
    else {
        f[t1]=t2;
        if(rnk[t1]==rnk[t2]) rnk[t2]++; //若两树一样高,那么合并后,高度加一。
    }
}




评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值