伸展树属于一种平衡二叉树。在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。主要分为四种情况Zig, Zag, Zig-zig, Zig-Zag.
1 Zig-Zig
2. Zig-Zag
代码实现:
package com.lww.tree;
import com.lww.ADT.MyStack;
/**
* 伸展树的实现
* @author 黎威威
*
* @param <T>
*/
public class SplayTree<T extends Comparable<? super T>> {
/**
* 伸展树结点
* @param <T>
*/
private static class SplayNode<T> {
public SplayNode(T data) {
this(data, null, null);
}
public SplayNode(T data, SplayNode<T> lt, SplayNode<T> rt) {
element = data;
left = lt;
right = rt;
}
T element; // 数据域
SplayNode<T> left; // 左孩子
SplayNode<T> right; // 右孩子
}
private SplayNode<T> root; //树根结点
public SplayTree(){
root=null;
}
/**
* Zig旋转,以左孩子为旋转轴进行旋转
* 1 2
* / \ / \
* 2 z --> x 1
* / \ / \
* x y y z
* @param k2
* @return 返回旋转后子树的根节点
*/
private SplayNode<T> rotateWithLeftChild(SplayNode<T> k1) {
SplayNode<T> k2 = k1.left;
k1.left = k2.right;
k2.right = k1;
return k2;
}
/**
* Zag旋转,以右孩子为旋转轴进行旋转
* 1 2
* / \ / \
* z 2 --> 1 y
* / \ / \
* x y z x
* @param k2
* @return
*/
private SplayNode<T> rotateWithRightChild(SplayNode<T> k1) {
SplayNode<T> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
return k2;
}
/**
* 左Zig+Zig模型
* G P X
* / \ / \ / \
* P D X G A P
* / \ ---> /\ /\ ---> / \
* X C A B C D B G
* / \ / \
* A B C D
* @param k1
* @return
*/
private SplayNode<T> zigZigWithLeftChild(SplayNode<T> k1){
SplayNode<T> k2=rotateWithLeftChild(k1);
return rotateWithLeftChild(k2);
}
/**
* 右Zig+Zig模型
* G P X
* / \ / \ / \
* D P G X P B
* / \ ---> /\ /\ ---> / \
* C X C D A B G A
* / \ / \
* A B C D
* @param k1
* @return
*/
private SplayNode<T> zigZigWithRightChild(SplayNode<T> k1){
SplayNode<T> k2=rotateWithRightChild(k1);
return rotateWithRightChild(k2);
}
/**
* 左Zig+Zag模型
* G G X
* / \ / \ / \
* P D X D P G
* / \ ---> /\ ---> /\ / \
* C X P B C A B D
* / \ / \
* A B C A
* @param k1
* @return
*/
private SplayNode<T> zigZagRightRotate(SplayNode<T> k1){
k1.left=rotateWithRightChild(k1.left);
return rotateWithLeftChild(k1);
}
/**
* 右Zig+Zag模型
* G G X
* / \ / \ / \
* D P D X G P
* / \ ---> / \ ---> / \ /\
* X C A P D A B C
* / \ / \
* A B B C
* @param k1
* @return
*/
private SplayNode<T> zigZagLeftRotate(SplayNode<T> k1){
k1.right=rotateWithLeftChild(k1.right);
return rotateWithRightChild(k1);
}
/**
* 判断树中是否存在elem元素
* @param elem
* @return
*/
public boolean contains(T elem){
return contains(elem,root);
}
/**
* 将elem结点调整至t结点为根结点的子树根结点
* @param elem
* @param t
* @return
*/
private boolean contains(T elem, SplayNode<T> t) {
// TODO Auto-generated method stub
MyStack<SplayNode<T>> stack=new MyStack<>();
while(t!=null){
int compareResult = elem.compareTo(t.element);
if(compareResult<0){
stack.push(t);
t=t.left;
}
else if(compareResult>0){
stack.push(t);
t=t.right;
}
else{
break;
}
}
if(t==null) return false; //没有找到
//伸展操作
root=splay(stack,t);
return true;
}
/**
* 将结点t调整至根部
* @param stack 搜索结点t的路径结点
* @param t
*/
private SplayNode<T> splay(MyStack<SplayNode<T>> stack, SplayNode<T> t){
while(!stack.isEmpty()){
if(stack.size()>=2){
SplayNode<T> k1=stack.pop();
SplayNode<T> k2=stack.pop();
if(!stack.isEmpty())
{
if(stack.getTop().left == k2)
stack.getTop().left=t;
else
stack.getTop().right=t;
}
if(k1==k2.left){
if(t==k1.left){
//TODO:左Zig-zig模型
zigZigWithLeftChild(k2);
}
else{
//TODO:左Zig-zag模型
zigZagRightRotate(k2);
}
}
else if(k1==k2.right){
if(t==k1.right){
//TODO:右Zig-zig模型
zigZigWithRightChild(k2);
}
else{
//TODO:左Zig-zag模型
zigZagLeftRotate(k2);
}
}
}
else{
SplayNode<T> k1=stack.pop();
if(t==k1.left){
//TODO:Zig模型
rotateWithLeftChild(k1);
}
else{
//TODO:Zag模型
rotateWithRightChild(k1);
}
}
}
return t;
}
public boolean insert(T x){
root=insert(x,root);
contains(x,root); //将调整至root
return true;
}
public SplayNode<T> insert(T element,SplayNode<T> k1){
if(k1==null) return new SplayNode<T>(element);
int compareResult=element.compareTo(k1.element);
if(compareResult<0)
k1.left=insert(element,k1.left);
else if(compareResult>0)
k1.right=insert(element,k1.right);
else
;//Duplicate; Do nothing
return k1;
}
public boolean Remove(T x) {
if (contains(x, root)) {
/**
* 此时X就是根结点
*/
SplayNode<T> k1 = root.left, k2 = root.right;
if (k1 != null) {
root=findMax(k1);
root.right=k2;
} else
root = k2;
return true;
} else
return false;
}
/**
* 寻找最大的结点
* @return
*/
public T findMax(){
root=findMax(root);
return root!=null? root.element:null;
}
/**
* 寻找以t为根的子树最大元素
* @param t
* @return
*/
private SplayNode<T> findMax(SplayNode<T> t) {
// TODO Auto-generated method stub
if(t==null) return null;
MyStack<SplayNode<T>> stack=new MyStack<>();
while (t.right!= null) {
stack.push(t);
t=t.right;
}
t=splay(stack,t);
return t;
}
/**
* 寻找最小的结点
* @return
*/
public T findMin(){
root=findMin(root);
return root!=null? root.element:null;
}
/**
* 寻找以t为根的子树最大元素
* @param t
* @return
*/
private SplayNode<T> findMin(SplayNode<T> t) {
// TODO Auto-generated method stub
if(t==null) return null;
MyStack<SplayNode<T>> stack=new MyStack<>();
while (t.left!= null) {
stack.push(t);
t=t.left;
}
t=splay(stack,t);
return t;
}
/**
* 非递归前序遍历
*/
public void preOrderPrint(){
MyStack<SplayNode<T>> stack=new MyStack<>();
if(root==null) return;
/*版本一
* AvlNode<T> t=null;
stack.push(root);
while(!stack.isEmpty()){
t=stack.pop();
System.out.print(t.element+":");
System.out.print(t.left!=null?t.left.element+" , ":"NULL"+" , ");
System.out.print(t.right!=null?t.right.element:"NULL");
System.out.println();
if(t.right!=null) stack.push(t.right);
if(t.left!=null) stack.push(t.left);
}*/
/**版本二**/
while(root!=null){
System.out.print(root.element + ":");
System.out.print(root.left != null ? root.left.element + " , " : "NULL" + " , ");
System.out.print(root.right != null ? root.right.element : "NULL");
System.out.println();
stack.push(root);
root=root.left;
}
SplayNode<T> t = null;
while (!stack.isEmpty()) {
t = stack.pop();
if(t.right!=null){
SplayNode<T> t0=t.right;
while(t0!=null){
System.out.print(t0.element + ":");
System.out.print(t0.left != null ? t0.left.element + " , " : "NULL" + " , ");
System.out.print(t0.right != null ? t0.right.element : "NULL");
System.out.println();
stack.push(t0);
t0=t0.left;
}
}
}
}
public static void main(String[] args){
SplayTree<Integer> tree=new SplayTree();
for(int i=3;i<=10000;i=i+2){
tree.insert(i);
tree.insert(i-1);
}
tree.insert(32);
tree.insert(1);
for(int i=2;i<=10000;i++)
tree.contains(i);
tree.preOrderPrint();
}
}