1. 程式人生 > >Splay Tree 伸展樹

Splay Tree 伸展樹

寫在前面:我是巨菜……程式碼巨醜~請各種大牛不要鄙視……

Splay也就是傳說中的伸展樹~以前很想學,但是因為旋轉比較暈,所以一直沒學~這回因為決定學了,所以就看了看,寫了寫。經歷了3個小時的摸索……終於寫出來了……

首先說我用的題,是一道專門測平衡樹的題:

 給出N(N<=1000000)個操作,然後有N行,每行兩個數,ch和k
ch=1表示插入一個值為k的數
ch=2表示查詢第k小的數
ch=3表示刪除值為k的數(k一定存在)
我之前的平衡樹速度測試和學習都用的這道題(P.s.據說是陳啟峰神牛的資料)。Splay是所以神奇就是因為它的靈活,我還是按照我的習慣來說說這個東西。想看的更具體一點呢,可以去看看sqybi神牛的經典Splay教程《The Magical Splay》(地址:

http://www.oibh.org/bbs/viewthread.php?tid=23645&highlight=splay

首先,平衡樹的重要操作肯定少不了旋轉,Splay的旋轉就是個很悲劇的東西。因為splay的精髓在於把一個點旋轉到任意一個位置,所以要記錄每個點的父親。但是一旦旋轉中出現了父親,很多東西都很IMBA~

還是一樣,兩種旋轉ZIG和ZAG。ZIG(x)表示當x為它父親的左兒子時,將x旋轉到父親的位置上的操作,ZAG則反之。(這個東西要認真寫,差一點都會出大問題。)

然後就是伸展樹的精髓,就是Splay(x,y)過程,就是將x旋轉到y的兒子的位置,當y=0的時候旋轉到根。這樣就一共有6種情況,寫寫還可以。

然後就是怎麼用它來維護樹的平衡,說白了就是每次搞完了之後就將操作的那個點旋轉到根去就好。所有操作中比較神奇的應該說是刪除操作,首先找到您要刪除的節點轉到根上,然後找到比它大的最小的數和比它小的最大的數。(P.s.說白了就是找前驅和後繼),這個時候要看這兩個指標是否為空,如果是空,那麼直接把root改下就好。反之,如果左右都有,那麼將前驅轉到根上,然後將後繼轉到前驅的右兒子上,細心的人這時候就發現,根的右兒子的左兒子只有一個元素,就是我們要刪掉的那個元素。這樣就結了,幹掉這個點就好……

實測情況:

P.s.skyprophet那個是我以前的treap,cqf那個是陳啟峰神牛的SBT,splay就是我這會寫的東西了。~~

【程式碼】: