平衡樹——Splay
阿新 • • 發佈:2021-06-18
前言
學了 FHQ Treap ,據說那玩意能代替 Splay,所以就懶得學Splay 了 = =,直到老呂給我們講了 Splay,發現這玩意確實也挺香滴 /se
這兒主要參考 attack 學長的部落格,所以這就不再詳細寫了(主要是懶)
簡介
Splay 也是平衡樹的一種,所以它還是基於二叉搜尋樹的
主要思想:對於查詢頻率較高的節點,使其處於離根節點相對較近的節點
Splay 的特色操作:rotate 和 Splay
操作
具體操作和 Treap 類似,但是這不是父親向下挪,而是兒子向上挪(效果其實一個樣),相比於 Treap,Splay 要維護每個點父親的資訊
rotate
使得一個點挪到它的父親節點
- 當 X 是 Y 的左孩子
R R
\ \
Y X
/ -> / \
X A Y
/ \ / \
A B B C
- 當 X 是 Y 的右孩子
R R \ \ Y X / \ -> / \ A X Y C / \ / \ B C A B
發現:如果讓 X 成為 Y 的父親,只會影響三個點關係,B 與 X, X 與Y, X 和 R
規律:
B 成為 Y 的哪個兒子與 X 是 Y 的哪個兒子是一樣的
Y 成為 X 的哪個兒子與 X 是 Y 的哪個兒子相反
X 成為 R 的哪個兒子與 Y 是 R 的哪個兒子相同
那麼只需要得出每個點是它父親的什麼兒子就好了
Splay
把 x 節點挪到 to 節點
- 如果 to 是 x 的爸爸,直接把 x 旋上去
- 如果 x 和它爸爸,爺爺在同一條直線就先旋父親,再旋兒子
- 若 x 和它爸爸,爺爺不在同一條直線上,旋兩次 x 就好
Insert
在二叉樹中找到它的位置,插入,然後把它轉到根節點,就好了
Delete
找到目標節點,把它轉到根,分情況討論
- 該節點有重複值,直接減
- 它沒有左右兒子:直接刪
- 它沒有左兒子:把根置為右兒子
- 它既有左兒子,也有右兒子:在左兒子中找到最大值,旋轉到根,右兒子當做新根的右兒子
Rank
找到它的位置,根據子樹大小確定它的排名
Kth
根據子樹大小確定它的位置
query pre(rec)
和 Treap 一個樣
至於程式碼
還沒加工出來 = =