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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_36561697/article/details/96753508

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

//递归形式的路径压缩
int getf(int v)
{
    if(v==f[v]) return v;
    return f[v]=getf(f[v]);
}
int find(int x)//非递归写法,不太好记但是更快,列几组数据试一下也不难理解
{
	int r=x,q;
	while(r!=father[r])
		r=father[r];
	while(x!=r)
	{
		q=father[x];
		father[x]=r;
		x=q;
	}
	return r;
}

按秩合并
这里也可以应用一个简单的启发式策略——按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。为了保存秩,需要额外使用一个与 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]++; //若两树一样高,那么合并后,高度加一。
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36561697/article/details/96753508