伸展树(splay tree)
通常在任意数据结构的生命期内,不仅执行不同操作的概率往往极不均衡,而且各操作之间具有极强的相关性,并在整体上多呈现出极强的规律性。其中最为典型的,就是所谓的“数据局部性”(data locality),这包括两个方面的含义:
1)刚刚被访问过的节点,极有可能在不久之后再次被访问到
2)将被访问的下一节点,极有可能就处于不久之前被访问过的某个节点的附近
因此,只需将刚被访问的节点,及时地“转移”至树根(附近),即可加速后续的操作。“即用即前移”的启发式策略,将最为常用的数据项集中于列表的前端,从而使得单次操作的时间成本大大降低。
1.逐层扩展
每访问过一个节点之后,随即反复地以它的父节点为轴,经适当的旋转将其提升一层,直至最终成为树根。
随着节点E的逐层上升,两侧子树的结构也不断地调整,故这一过程也称作伸展(splaying),而采用这一调整策略的二叉搜索树也因此得名。
目前的策略仍存在致命的缺陷对于很多访问序列,单次访问的分摊时间复杂度在极端情况下可能高达O(n)。
2.双层伸展
为克服上述伸展调整策略的缺陷,一种简便且有效的方法就是:将逐层伸展改为双层伸展。具体地,每次都从当前节点v向上追溯两层(而不是仅一层),并根据其父亲p以及祖父g的相对位置,进行相应的旋转。以下分三类情况,分别介绍具体的处理方法。
* zig-zig/zag-zag
如此连续的两次zig旋转,合称zig-zig调整。另一种完全对称的情形——通过连续的两次逆时针旋转实现调整,合称zag-zag操作。
* zig-zag/zag-zig
如此zig旋转再加zag旋转,合称zig-zag调整。另一完全对称的情形——通过zag旋转再加zig旋转实现调整,合称zag-zig操作。
* zig/zag
只需围绕p = r做顺时针旋转zig(p),即可如图(b)所示,使v最终攀升至树根,从而结束整个伸展调整的过程。
zag调整与之对称。
3.伸展树的实现
伸展树接口定义
基于BST类,可定义伸展树模板类Splay
#include "../BST/BST.h" //基于BST实现Sp