伸展树,也叫作分裂树,是一种二叉搜索树,可以在内完成插入、查找和删除操作。
在任意数据结构的生命周期内执行不同操作的概率往往极不均衡,而且各操作之间有极强的相关性,在整体上多呈现极强的规律性,其中最为典型的就是数据局部性。数据局部性包括时间局部性和空间局部性。伸展树正是基于数据的时间局部性和空间局部性原理产生的。
1、时间局部性和空间局部性的原理
(1)刚刚被访问的元素,极有可能在不久后再次被访问
(2)刚刚被访问的元素,它的相邻节点也很有可能被访问
伸展树的实现更为便捷,它无须时刻保持全树平衡,任意节点的左右子树高差无限制。伸展树的单次搜索也可能需要n次操作,但可以在任意足够长的真实操作序列中保持均摊意义上的高效率。伸展树可以保证m次连续搜索操作的复杂度为,而不是。伸展树的优势在于不需要记录平衡因子、树高、子树大小等额外信息,所以适用范围更广,对m次连续搜索操作具有较高的效率。
考虑到局部性原理,伸展树会在每次操作后都将被访问的节点旋转至树根,加速后续的操作。当然,旋转前后的搜索树必须相互等价。这样,查询频率高的节点应当经常处于靠近树根的位置。旋转的巧妙之处在于不打乱数列中数据大小的关系(中序有序性)的情况下,所有操作的均摊复杂度仍为
2、右旋和左旋
伸展操作是在保持伸展树有序性的前提下,通过一系列旋转将伸展树中的元素x调整到goal的子节点,若goal=0,则将元素x旋转到树的根部。伸展操作包括右旋和左旋两种基本操作。
与Treap的旋转方式相同,但左旋右旋可以写成一段代码。
void Rotate(int x)//x作为儿子出现
{
int y=tr[x].fa,z=tr[y].fa;
in