并查集是一种树型的数据结构,
用于处理一些不相交集合(disjoint sets)的合并及查询问题。
常常在使用中以森林来表示。
朴素:
int Find(int x)
{
if(fat[x]==x) return x;//fat是指父节点
return Find(fat[x]);
}
void unionn(int x,int y)
{
if(Find(x)!=Find(y)) fat[Find(x)]=Find(y);
return ;
}
+启发式合并
在朴素的基础上,可以优化合并的过程:
每次将较小的集合并入较大的集合中。
这样,并查集的时间复杂度就会降至:(O(nlog_2n))
启发式代码:
void unionn(int x,int y){
x=Find(x); y=Find(y);
if(siz[x]>siz[y]) swap(x,y);
fat[x]=y; siz[y]+=siz[x];
}
+路径压缩
我们会发现,如果只是单纯的查找集合。
那么树中中间节点就是冗余的。
如何我们将这些中间节点在访问过后直接将它们的父亲指向集合的代表元。
在后续访问中,就不会有这些冗余了。
(如果强调节点的父子关系,就不能使用路径压缩)
时间复杂度:随机数据极快,上界(O(nlog_2n))。
int Find(int x){
return (fat[x]==x)? x : fat[x]=Find(fat[x]);
}
void unionn(int x,int y){
x=Find(x); y=Find(y);
if(siz[x]>siz[y]) swap(x,y);
fat[x]=y; siz[y]+=siz[x];
}