1. 程式人生 > 其它 >平衡樹——Splay

平衡樹——Splay

前言

學了 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 一個樣

至於程式碼

還沒加工出來 = =