伸展树

伸展树提出的想法基于计算机基础概念的时间局部性原理和空间局部性原理:当某一个节点被访问,那么在不久之后它很有可能被访问,而且它的相邻节点也很有可能被访问。
所以当访问一棵二叉查找树的一个比较深的节点时,如果能够使这个被访问的节点移动到根上使得它下次最快被访问,再如果不仅使得被访问的节点下次被更快访问,而且能使得访问路径上所有节点下次能更快被访问,那这种数据结构就很有意思了。
实现想法1:单旋转
单旋转的规则是:将要旋转的两个节点视为与其他节点是分离不相连的,从下往上,逐个旋转,以被访问点为固定点,轴在左上则左旋转120度,轴在右上就右旋转120度。如果有占位的情况,则断孩子,连兄弟,过继孩子。

现在将A节点通过单旋转的方法实现伸展树
原始图:
伸展树_第1张图片
将B\A这两个节点提出来,左旋转变成B/A,再将A连上C,B连上1,由于B左旋转的时候占了2的位置,所以A断开孩子2,保持与兄弟B的连接,孩子2过继的给B,由于2原来在B的右侧,因此成为B的右子树。
伸展树_第2张图片
将A/C这两个节点提出来,右旋转变成A\C,再将A连上D,B连上A,由于C右旋转的时候占了3的位置,所以A断开孩子3,保持与兄弟C的连接,孩子3过继的给C,由于3原来在C的左侧,因此成为C的左子树。
伸展树_第3张图片
同样的规则,最终A移动到了树根,这样构成一颗新的二叉查找树。
伸展树_第4张图片
伸展树_第5张图片
在例子中可以看到,虽然单旋转使得A的访问速度提高了(因为移动到根节点),但是访问路径上的C的深度却加大了,因此这不是一种优秀的方法。
实现想法2:展开
如果被访问节点只有父亲,没有祖父,那么只需要通过单旋转的方式展开;如果被访问的节点有祖父,那么展开有两种:一种是之字形展开,一种是一字形展开。
之字形展开的规则:
LR的之字形:Z的左儿子是Y,Y的右儿子是X,对X进行展开。自下向上,先左旋转,然后右旋转。如果有占位的情况,则断孩子,连兄弟,过继孩子。对称的情况RL的之字形则是先右旋转然后左旋转。
一字形展开的规则:
八点钟方向的一字形:Z的左儿子是Y,Y的左二子是X,对X进行展开。自下向上,两次右旋转。如果有占位的情况,则断孩子,连兄弟,过继孩子。对称的情况四点钟方向的一字形则是两次左旋转。
原始图:
伸展树_第6张图片
对A来说,它左上角有父亲B,B右上角有A的祖父C,这是LR的之字形。
伸展树_第7张图片
对A来说,它的右上角由父亲D,D的右上角有A的祖父E,这是八点钟方向的一字形。
伸展树_第8张图片
在例子中可以看出,展开不仅使得A的访问速度提高了,而且也提高了访问路径上大部分节点的访问速度。
代码未完待续。。。

你可能感兴趣的:(数据结构与算法)