伸展樹(Splay)復雜度證明
本文用勢能法證明\(Splay\)的均攤復雜度,對\(Splay\)的具體操作不進行講述。
為了方便本文的描述,定義如下內容:
在文中我們用\(T\)表示一棵完整的\(Splay\),並(不嚴謹地)用\(|T|\)表示\(T\)這棵\(Splay\)的節點數目。
如無特殊說明,小寫英文字母(如\(x\),\(y\),\(z\))在本文中表示\(T\)的一個節點,並(不嚴謹地)用\(|x|\)表示以節點\(x\)為根的子樹的大小,\(x\in T\)表示節點\(x\)在\(T\)中。
一般我們默認\(x‘\)代表節點\(x\)在經過了上下文中描述的操作以後的狀態,因此對應的\(x\)代表之前的狀態。
我們用\(\Phi(T)\)表示整棵\(Splay\)的勢能函數,\(\phi(x)\)則表示節點\(x\)對\(T\)貢獻的勢能。
=============================================
先來講一下我們的勢能函數,我們定義:
\[\phi(x)=\log|x|\]
\[\Phi(T)=\sum_{x\in T}\phi(x)\]
可以發現,對於任意時刻,因為\(|x|\geq 1\),因此\(\log|x|\geq 0\),從而得到\(\Phi(T)\geq 0\),因此勢能函數是合法的。同時\(\forall |x|\leq |T|\),因此我們總有\(\Phi(T)\leq |T|\log|T|\)
下面考慮一次伸展操作對於勢能函數的影響。由於我們可以把從根向下查找的代價計算到伸展過程中對應的旋轉操作上,此時旋轉操作復雜度不變,只是常數增大,從而忽略了查找對復雜度的影響。我們可以簡單地通過增大勢的單位來支配隱藏在操作中的常數。因此我們只需證明對於一次伸展操作的所有旋轉操作,其復雜度是均攤\(O(\log|T|)\)的,我們就完成了對\(Splay\)復雜度的證明。
\(1\)、\(zig\)操作
由於\(zag\)操作與\(zig\)相似,因此只需要證明\(zig\)即可。
假設我們\(zig\)的對象是\(x\),其父親為\(y\),顯然在旋轉以後,只有\(x\)
\[\Delta\Phi(T)=\phi(x‘)+\phi(y‘)-\phi(x)-\phi(y)\]
顯然\(\phi(x‘)=\phi(y)\),且\(\phi(x‘)\geq \phi(y‘)\),因此消去\(\phi(x‘)\)與\(\phi(y)\),並將\(\phi(y‘)\)替換為\(\phi(x‘)\),有:
\[\Delta\Phi(T)\leq \phi(x‘)-\phi(x)\]
因此\(zig\)操作的均攤代價為\(O(1+\phi(x‘)-\phi(x))\),其中\(O(1)\)代表旋轉操作本身的復雜度,而在一次伸展操作中也只會有一次\(zig\)操作,因此這額外的\(O(1)\)代價不會對分析造成影響,因此我們可以只關心其中的\(O(\phi(x‘)-\phi(x))\)。
\(2\)、\(zig-zig\)操作
由於\(zag-zag\)操作與\(zig-zig\)相似,因此只需要證明\(zig-zig\)即可。
假設我們\(zig-zig\)的對象是\(x\),其父親為\(y\),其祖父為\(z\),與\(zig\)操作類似,勢能變化量為:
\[\Delta\Phi(T)=\phi(x‘)+\phi(y‘)+\phi(z‘)-\phi(x)-\phi(y)-\phi(z)\]
同樣地,由於\(\phi(x‘)=\phi(z)\),因此將它們消去:
\[\Delta\Phi(T)=\phi(y‘)+\phi(z‘)-\phi(x)-\phi(y)\]
而我們又有\(\phi(x‘)\geq \phi(y‘)\),\(\phi(x)\leq \phi(y)\),因此有:
\[\Delta\Phi(T)\leq \phi(x‘)+\phi(z‘)-2\phi(x)\]
推到這裏,我們先來做一個小工作,來證明\(\phi(x)+\phi(z‘)-2\phi(x‘)\)(註意與上面的式子不一樣)的值不大於\(-1\)。
假設\(|x|=a\),\(|z‘|=b\),那麽我們有:
\[\phi(x)+\phi(z‘)-2\phi(x‘)=\log|x|+\log|z‘|-2\log|x‘|\]
我們將\(\log\)合並,得到:
\[\phi(x)+\phi(z‘)-2\phi(x‘)=\log(\frac{|x||z‘|}{|x‘|^2})\]
由於\(|x‘|\geq a+b\)(可以結合旋轉過程思考一下),而\(\log\)是單調的,因此:
\[\phi(x)+\phi(z‘)-2\phi(x‘)\leq \log(\frac{ab}{(a+b)^2})\leq \log(\frac{ab}{2ab})\leq -1\]
證明完畢。現在我們已經知道\(zig-zig\)操作的攤還代價不大於:
\[O(1)+\phi(x‘)+\phi(z‘)-2\phi(x)\]
其中\(O(1)\)為旋轉操作的復雜度。由於之前的推導我們可以知道\(\phi(x)+\phi(z‘)-2\phi(x‘)\leq -1\),因此\(-1-(\phi(x)+\phi(z‘)-2\phi(x‘))\geq 0\),我們在攤還代價上加上這個非負數得到:
\[O(1)+\phi(x‘)+\phi(z‘)-2\phi(x)-1-(\phi(x)+\phi(z‘)-2\phi(x‘))\]
化簡一下,就得到:
\[O(1)+O(\phi(x‘)-\phi(x))-1\]
通過增大我們剛剛加的那個非負數以及勢的單位,我們就可以支配隱藏在\(O(1)\)中的常數,因此一次\(zig-zig\)操作的攤還代價為:
\[O(\phi(x‘)-\phi(x))\]
\(3\)、\(zig-zag\)操作
分析的過程和\(zig-zig\)操作完全一樣,之前分析用到的所有性質此時仍然適用,因此略過分析過程。其攤還代價依然為:
\[O(\phi(x‘)-\phi(x))\]
\(4\)、總結
綜上所述,除了最後一次旋轉可能增加\(O(1)\)的代價以外,其余操作的攤還代價只和我們伸展的對象\(x\)的勢有關。我們假設旋轉操作一共執行了\(n\)次,並用\(x_i\)來表示節點\(x\)在經過\(i\)次旋轉後的狀態,那麽整一個伸展操作的攤還代價就為:
\[O\Big(1+\sum_{i=1}^n\phi(x_i)-\phi(x_{i-1})\Big)\]
顯然除了\(\phi(x_n)\)與\(\phi(x_0)\)外,所有的勢都被抵消了,因此攤還代價為:
\[O(1+\phi(x_n)-\phi(x_0))\]
至此,我們不必關心\(\phi(x_0)\)的值了。此時\(x_n\)是整棵\(Splay\)的根,因此\(\phi(x_n)=\log|T|\)。我們成功的證明了一次伸展操作的攤還代價為\(O(\log|T|)\)。
伸展樹(Splay)復雜度證明