并差集的三大应用整理与总结

并查集的基本操作有三个:

  1. make(s):建立一个新的并查集,其中包含 s 个单元素集合。
  2. union(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在的集合不相交,如果相交则不合并。
  3. find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。
1.make(s):
本人理解的make就是对并差集初始化:
/*make()*/
for(int i=1;i<=n;i++)f[i]=i;

2.union(x,y)
1)

按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将比较矮的树作为子树,添加到较高的树中。为了保存秩,需要额外使用一个与 uset 同长度的数组,并将所有元素都初始化为 0。

void union(int x, int y)
{ 
    if ((x=find(x)) == (y=find(y))) return;
    if (rank[x]>rank[y])uset[y]=x; 
    else 
	{ 
        uset[x] = y; 
        if (rank[x]==rank[y])rank[y]++; 
    } 
} 



2)

按集合中包含的元素个数(或者说树中的节点数)合并。将包含节点较少的树根,指向包含节点较多的树根。这个策略与按秩合并的策略类似,同样可以提升并查集的运行速度,而且省去了额外的 rank 数组。

这样的并查集具有一个略微不同的定义,即若 uset 的值是正数,则表示该元素的父节点(的索引);若是负数,则表示该元素是所在集合的代表(即树根),而且值的相反数即为集合中的元素个数。

void union(int x, int y) 
{ 
    if ((x=find(x))==(y=find(y)))return; 
    if (uset[x]<uset[y]) 
	{ 
        uset[x]+=uset[y]; 
        uset[y]=x; 
    } else { 
        uset[y]+=uset[x]; 
        uset[x]=y; 
    } 
} 

另,当然平时我们也能简写成这样的形式:
void uinon(int x,int y)
{
	int a=find(x),b=find(y);
	if(a!=b)f[a]=b;
}

3.find(x)

这里给出启发式优化过后的代码:

int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值