路径压缩优化并查集大家一定很熟练了,那么它的复杂度是多少呢? O ( m α ( n ) ) O(m\alpha(n)) O(mα(n))?
的确,很多人都是这么说的,但是事实上它的复杂度是 O ( m log 1 + m / n n ) O(m\log_{1+m/n}n) O(mlog1+m/nn)的,并且能找到一种方法卡到这样的复杂度。
要卡并查集,首先要构造一种树——二项树。这种二项树还与普通的不太一样。
定义:在给定 j j j的情况下,二项树 T k T_k Tk定义如下:
- 若 k ≤ j k\leq j k≤j, T k T_k Tk是一个点。
- 若 k > j k>j k>j, T k T_k Tk是 T k − 1 T_{k-1} Tk−1的根结点增加一棵 T k − j T_{k-j} Tk−j的子树。

这棵树非常有意思,我们可以展开 T k − j T_{k-j} Tk−j,接着展开 T k − 2 j T_{k-2j} Tk−2j……
另外,也可以展开 T k − 1 T_{k-1} Tk−1,接着展开 T k − 2 T_{k-2} Tk−2……

容易发现,图5看起来像图4的路径压缩之后的结果,但是不完全一样。
如果首先按照图5的方式展开 j j j棵子树,再按图4展开,可以得到

此时,如果在根节点上再加一个点, j j j次访问 T 1 T_1 T1到 T j T_j Tj,那么路径压缩后可以得到图5外加一个点作为根的儿子。
也就是说,这棵二项树路径压缩后约等于没有路径压缩……只是将原来作为根结点父亲的那个点变成了儿子。
至于 T k T_k Tk的点数,通过数学归纳法可以发现不会超过 ( j + 1 ) k / j − 1 (j+1)^{k/j-1} (j+1)k/j−1个。
假设 m ≥ n m\geq n m≥n,令 j = m n , i = log j + 1 n 2 + 1 , k = i j j=\frac{m}{n},i=\log_{j+1}\frac{n}{2}+1,k=ij j=nm,i=logj+12n+1,k=ij,那么 T k T_k Tk的点数不超过 n 2 \frac{n}{2} 2n。接下来做 n 2 \frac{n}{2} 2n组操作,每次加入一个点作为根结点的父亲,然后对 T 1 T_1 T1到 T j T_j Tj逐个查询,每次查询的长度是 i + 1 i+1 i+1,同时查询的次数显然不超过 m m m。因此总操作次数为 n 2 j ( i + 1 ) \frac{n}{2}j(i+1) 2nj(i+1),即 O ( m log 1 + m / n n ) O(m\log_{1+m/n}n) O(mlog1+m/nn)。

这篇博客探讨了路径压缩优化的并查集在实际操作中的时间复杂度,指出其并非简单的O(mα(n)),而是O(mlog1+m/nn)。通过介绍二项树的概念,解释了如何构造特定的二项树来达到这个复杂度,并阐述了路径压缩后二项树的变化。文章借助数学归纳法分析了二项树的点数,并在m≥n的条件下,展示了如何进行2n组操作,每组包含m次查询,从而得出总操作次数的上界。
2429

被折叠的 条评论
为什么被折叠?



