Splay中的旋轉操作用單旋與雙旋的區別是什麼?

NOIP吧曾經討論過Splay的單雙旋轉的問題,然而哪種操作比較優?

或者說,兩者在效率上、代碼長度上的區別?


第一次有人邀請我回答問題ヽ(??ω?? )ゝ開森

雙旋的話tarjan證明了複雜度均攤為O(logn)。

單旋的話就是妥妥O(n)了啊,雖然不卡的話很快,但是單旋比較好寫。

如果不太記得雙旋怎麼寫(? ??_??)?的話可以寫單旋,一般能過,但是要注意千萬不要用單旋去寫LCT,因為一條鏈就可以卡掉(?_?我就這麼狗帶的)

如果會雙旋最好用雙旋咯!信Tarjan得永生⊙ω⊙


用單旋(單旋到根稱為move to root)會被卡是常識了。。對於單調數據,樹會退化成一條鏈,然後每次move最深的點就被卡掉啦~

而splay tree用的是雙旋(雙旋到根稱為splay),可以用勢能法證明splay是均攤 O(log n) 的。

具體來說,設旋轉的常數為 k ,定義:

  • size(r) :以r為根的子樹的大小;
  • rank(r)klog_2 size(r)
  • 勢函數 Phi :樹中所有結點的 rank 之和.

對於很不平衡的樹,Phi會變得很大。反之,對於較平衡的樹,Phi較小.

為了應用勢能分析法,我們需要先計算 Delta Phi:splay操作導致的勢能變化.我們對於每種情況分別討論,用 rank 表示操作後的 rank 函數。 xpg 為旋轉所影響到的結點.由 log 函數的凸性,可以得出:

egin{align} log x_1 + log x_2 leq 2log frac{x_1 + x_2}2\ = 2log(x_1+x_2) + 2\ leq 2log(x_1+x_2+r) + 2~(rgeq0) end{align}

log(x_1) + log(x_2) - 2 log(x_1+x_2+r) leq 2~(rgeq0)

對於Zig:

egin{align}DeltaPhi = rank

對於Zig-Zig:

egin{align}DeltaPhi = rank

對於Zig-Zag:

egin{align}DeltaPhi = rank

因此,對於zig-zig或zig-zag:

egin{split} 均攤代價 = 實際代價 + Delta Phi\ leq 2k + 3k(rank

將所有操作的均攤代價相加,可得整個splay操作的均攤代價為 3k(rank(root)?rank(x))=O(log n) 。zig操作會使均攤代價增加 k ,但zig操作至多只會有一次。

所以,一次splay操作的時間複雜度為均攤 O(log n)


單旋大法吼啊

開個氧氣就變O(1)的辣

↑:以上是偽科學,玩梗

事實上,單旋-&>Splay不平衡-&>勢能分析失效

對不起我的評論里總有人帶隊形.關評論了


Splay就是splay,怎麼能寫單旋的呢……單旋的那叫spaly……


單旋的都是邪教!


我寫過的所有splay題,單旋都比雙旋塊(霧

不過單旋複雜度確實不太對,但是出題人基本不會刻意去卡,因為他們覺得會splay的基本上都寫的雙旋。

但是如果正式比賽你為了省幾行代碼要寫單旋,就作大死了。。。誰知道出題人會出什麼樣的數據呢


答主手工模擬一下單旋過程吧。隨便轉個兩下(連續的zig或zag)就會發現被轉過去的那個子樹形態依舊。於是只要給你一條鏈就被卡飛啦。


單旋複雜度是錯的呢。。


一直這樣寫....應該不會被卡吧

void Splay(int rt,int x)
{
while(x!=rt)
{
if(fa[x]!=rt) Rotate(rt,fa[x]);
Rotate(rt,x);
}
}


效率上雙旋快,單旋不科學的

代碼長度上都是一行,不過單旋短一點


splay雙旋均攤o(logn),但是類似sbt會被人字型數據卡成o(n)。

splay單旋均攤也是o(logn),會被線型數據卡成o(n)。

treap裡面隨機的權重其實沒多大用,只是為了隨機旋轉防止被卡。

splay單旋其實也可以防止被卡,但是不能在splay的過程中模仿treap隨機旋轉,因為要rotate to root。

防止被卡的辦法是在每次操作完之後加上splay(rand()%n)。

口胡輕噴。


推薦閱讀:

如何評價洛谷OJ?
退役OIer和退役MOer在解決數學問題的思路上有何不同?
如何看待APIO2016的練習賽網址中出現「漢語(中華民國)」的語言選項?
如何能夠不通過陝西省NOIP初賽?

TAG:OI | 演算法與數據結構 | ACM競賽 |