平衡树——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 一个样

至于代码

还没加工出来 = =

平衡树——Splay

上一篇:new Set()


下一篇:好玩的对象存储