并查集
等价关系:对称,自反,传递
等价类:集合划分
操作:
- 查:找当前集合属于哪一个等价类
- 并:合并两个等价类
实现:树
- Union, Find操作仅涉及fa,故只需存储fa
- 静态链表建树,
S[element] = fa, s[root] = 0
,set name = root index
应用:动态等价性问题
Initialize N disjoint sets;
while (read in a ~ b) {
if (!(Find(a) == Find(b))) Union the two sets;
}
while (read in a and b) {
if (Find(a) == Find(b)) output(ture);
else output(false);
}
操作:
- SetUnion
- Find
问题:合并的最坏情况导致其退化为单链,find操作\(T(N)=O(N)\).
解决1:按大小合并
实现:
- 集合大小记录:
S[root] = -size;
- 由于节点编号均为正数,故使用负数来记录大小信息
引理:按大小合并时\(\text{height}(T)\leqslant\lfloor\log_2N\rfloor+1\)
时间复杂度:\(N\)次合并,\(M\)次查找,\(O(N+M\log_2N)\)
解决2:按高度合并
实现:S[root] = -height
路径压缩:让所有儿子都直接指向根,find操作复杂度降为\(O(1)\)
实现:在find同时压缩
SetType Find ( ElementType X, DisjSet S ) {
if ( S[ X ] <= 0 ) return X;
else return S[ X ] = Find( S[ X ], S );
}
SetType Find ( ElementType X, DisjSet S )
{ ElementType root, trail, lead;
for ( root = X; S[ root ] > 0; root = S[ root ] )
; /* find the root */
for ( trail = X; trail != root; trail = lead ) {
// lead带着trail将路径上所有节点连上root
lead = S[ trail ] ;
S[ trail ] = root ;
} /* collapsing */
return root ;
}
Union-by-height无法和路径压缩合并使用:路径压缩导致树高改变
按秩(集合大小等指标)合并 + 路径压缩:
- 引理:\(k_1M\alpha(M,N)\leqslant T(M,N)\leqslant k_2M\alpha(M,N)\)
- 其中\(\alpha\)为Ackermann函数的反函数\(\alpha\leqslant4\)
\[
A(i,j)=\left\{\begin{array}{ll}2^j&i=1,j\geqslant1\\
A(i-1,2)&i\geqslant2,j=1\\
A(i-1,A(i,j-1))&i\geqslant2,j\geqslant2\end{array}\right.
\]