伸展树的设计有两种设计模式,第一种 自低向上的设计方式,第二种 设计方式 自顶向下的设计方式,对于由低向上的设计,每一个结点树保留指向其父结点的的额外的结点, 第二种方式由sedgewick大神的《算法》一书感谢这一
位大神。
伸展树又叫自适应查找树,实质上二叉搜索树的的变形,允许各种类型的二叉树操作,操作的时间复杂度
O(logN),但是伸展树并不能保障最坏的情况,这个时间复杂度是平均的值,适合任意的操作序列。
右连接:将当前根以及右子树连接到 右 树上 ,当前节点 左子树结点 作为新根(下一次遍历的当前节点);
提示: nullPoint 表示逻辑上的 null的概念 ,header 结点 记录 左树和 右树的首地址,不能丢弃否则找不到 分解之后的左右树
局部变量 LeftTreeMax。rightTreeMin 为了跟随向下遍历 时候 增加 左 右 树长度
/** 伸展树
* nullpoint 表示逻辑上的null
* 建立空树 左 树 和 右 树
*/
public class SplayTree >{
private static class BinaryNode{
AnyType Element;
BinaryNode left;
BinaryNode right;
public BinaryNode(AnyType Element) {
this(Element,null,null);
}
public BinaryNode(AnyType element, BinaryNode object, BinaryNode object2) {
this.Element=element;
this.left=object;
this.right=object2;
}
}
private BinaryNode root;
private BinaryNode nullNode;
// for Splay 记录 左树 和右树的首地址
private BinaryNode header=new BinaryNode(null);
// Use between different inserts
private BinaryNode newNode=null;
/** 自顶向下的伸展时候
* 创建 两个空树 */
private BinaryNode splay(AnyType x,BinaryNode t)
{
BinaryNode leftTreeMax,rightTreeMin;
header.left=header.right=nullNode;
leftTreeMax=rightTreeMin=header;
nullNode.Element=x;
while(true)
{
if(x.compareTo(t.Element)<0)
{
if(x.compareTo(t.left.Element)<0) // 一字型旋转 不是简单单旋 ,点 比 X,Y小,X,Y连接到右树上
t=roateWithLeftChild(t);// AVL
if(t.left ==nullNode)
break;// 没有找到
// Link Right 右连接:将当前根及其右子树连接到右树上。左子结点作为新根,向下遍历更新 rightTreeMin
rightTreeMin.left=t;
rightTreeMin=t;
t=t.left;// 左 结点 是 目标 Z 的子树下
}
else if(x.compareTo(t.Element)>0)
{
if(x.compareTo(t.right.Element)>0)
{
t=roateWithRightChild(t);
if(t.right==nullNode)
break;
leftTreeMax.right=t;
leftTreeMax=t;// 向下移动 用 header结点 记录 初始位置不怕 首地址 丢失
t=t.right;
}
}
else {
break;
}
// 找到之后合并
leftTreeMax.right=t.left;
rightTreeMin.left=t.right;
// header 结点 记录 右树 最开始地址 ,header 的左子树 记录比所查找点 大的结点 由 rightTreeMin.left=t
t.left=header.right;
t.right=header.left;
return t;
}
}
/**
* 将 插入 X 做成 新根 每插入 一次 进行splay*/
public void insert(AnyType x)
{
if(newNode==null)
newNode=new BinaryNode(null);
newNode.Element=x;
if(root==nullNode)
{
newNode.left=nullNode;
newNode.right=nullNode;
root=newNode;
}
else // 围绕新插入值 x 伸展开展开 root ,root。left 伸展开 之后 值一定比x小,已经存在 不insert
{
root=splay(x, root);
if(x.compareTo(root.Element)<0)
{
newNode.left=root.left;
newNode.right=root;
root.left=nullNode;
root=newNode;
}
else if(x.compareTo(root.Element)>0)
{
newNode.right=root.right;
newNode.left=root;
root.right=nullNode;
root=newNode;
}
else {
return;
}
newNode=null;// 为了下一次插入 分配 不同地址的 结点。
}
}
/**查找目标经过旋转 到 中间派*/
private BinaryNode roateWithLeftChild(BinaryNode k1) {
BinaryNode k2=k1.left;
k1.left=k2.right;
k2.right=k1;
return k2;
}
private BinaryNode roateWithRightChild(BinaryNode k2) {
BinaryNode k1=k2.right;
k2.right=k1.left;
k1.left=k2;
return k1;
}
}