上一篇主要基于父节点形式的自底向上的设计实现伸展树,这一篇将实现基于左右辅助树的自顶向下的设计。
这种方式不需要节点存储其父节点的指针。当我们沿着树向下搜索某个节点x时,将搜索路径上的节点及其子树移走。构建两棵临时的树——左树和右树。没有被移走的节点构成的树称为中树。且有以下原则:
1)当前节点x是中树的根;
2)左树L保存小于x的节点且L上的每个节点值都要比中树的小,故当从中树移动接到到左树L时一定在L的右子树;
3) 右树R保存小于x的节点且R上的每个节点值都要比中树的大,故当从中树移动接到到右树R时一定在R的左子树;
同自低向上类似,在旋找过程中也存在以下类型:
zig or zag旋转:
zig-zig or zag-zag旋转:
zig-zag or zag-zig旋转:
得到左树L,中树和右树后,最终合并:
需要注意的是,虽然存在zig,zig-zig or zig-zag类型,但简化来看,其实质只是:小于根的时候就是右连接,大于根的时候是左连接,其他的情况只不过是先做了别的操作。
C++类实现:
tree.h
//从顶向下
class splay_tree{
private:
node *root;
public:
splay_tree();
~splay_tree();
void postorder();
void inorder();
node *Find(eletype x);
node *Findmax();
node *Splayfromtop(eletype x);
void Insert(eletype x);
void Remove(eletype x);
void Destroy();
private:
void postorder(node*t)const;
void inorder(node*t)const;
node *Find(node*t,eletype x);
node *Findmax(node*t);
void singleRotaLeft(node*&t);
void singleRotaRight(node *&t);
node *Splayfromtop(node*t,eletype x);
node *Insert(node*&t,eletype x);
node *Remove(node*&t,eletype x);
void Destroy(node*&t);
};
tree.cpp
/***************Splay tree from top***********************/
splay_tree::splay_tree():root(NULL){}
splay_tree::~splay_tree(){Destroy(root);}
void splay_tree::postorder(node*t)const{
if(t){
postorder(t->lson);
postorder(t->rson);
cout<<t->val<<" ";
}
}
void splay_tree::postorder(){
cout<<"后序:"<<endl;
postorder(root);
cout<<endl;
}
void splay_tree::inorder(node*t)const{
if(t){
inorder(t->lson);
cout<<t->val<<" ";
inorder(t->rson);
}
}
void splay_tree::inorder(){
cout<<"中序:"<<endl;
inorder(root);
cout<<endl;
}
node*splay_tree::Find(node*t,eletype x){
if(t==NULL||x==t->val)return t;
if(x<t->val)return Find(t->lson,x);
else
return Find(t->rson,x);
}
node *splay_tree::Find(eletype x){
node*p= Find(root,x);
if(p==NULL){return p;}
if(p!=root){root=Splayfromtop(root,x);}
return root;
}
node *splay_tree::Findmax(node*t){
if(t==NULL){cout<<"empty tree!"<<endl;return t;}
node *p=t;
while(p->rson)p=p->rson;
return Splayfromtop(t,p->val);
}
node* splay_tree::Findmax(){
root=Findmax(root);
return root;
}
void splay_tree::singleRotaLeft(node*&t){
node*k1=t->rson;
t->rson=k1->lson;
k1->lson=t;
t=k1;
}
void splay_tree::singleRotaRight(node*&t){
node*k1=t->lson;
t->lson=k1->rson;
k1->rson=t;
t=k1;
}
node *splay_tree::Splayfromtop(node*t,eletype x){
node *l,*r,header;
header.lson=header.rson=NULL;
l=r=&header;
if(t==NULL)return t;
while(t&&t->val!=x){
if(x<t->val)//x is left
{
if(t->lson==NULL)break;
if(x<t->lson->val)//zig-zig
{singleRotaRight(t);
if(t->lson==NULL)break;//else next loop for zig
}
//右连接,把树根节点和右子数连接到右树
r->lson=t;
r=t;//r is newest node
t=t->lson;//update the root
}
else if(x>t->val)
{if(t->rson==NULL)break;
if(x>t->rson->val)//zag-zag
{singleRotaLeft(t);
if(t->rson==NULL)break;
}
//左连接
l->rson=t;
l=t;
t=t->rson;
}
else //is root
break;
}
//every lopp for only one zig or zag,double rotate for next loop
// merge the left right and original
l->rson=t->lson;
r->lson=t->rson;
t->lson=header.rson;//left tree
t->rson=header.lson;//right tree
return t;
}
node *splay_tree::Splayfromtop(eletype x){
root= Splayfromtop(root,x);
return root;
}
node* splay_tree::Insert(node*&t,eletype x){
if(t==NULL){t=(node*)malloc(sizeof(node));t->lson=t->rson=NULL;t->val=x;
return t;
}
if(x==t->val) return t;
else// not root
{node *tmp=t;node *qre=NULL;
while(tmp){qre=tmp;
if(x<tmp->val)tmp=tmp->lson;
else if(x>tmp->val)tmp=tmp->rson;
else break;
}
if(tmp==NULL)// no x
{node *X=new node();X->val=x;
if(qre->val>x)qre->lson=X;
else qre->rson=X;
tmp=X;
}
t=Splayfromtop(t,tmp->val);
}
return t;
}
void splay_tree::Insert(eletype x){
root=Insert(root,x);
}
node *splay_tree::Remove(node*&t1,eletype x){
if(t1==NULL){cout<<"empty tree!"<<endl;exit(1);}
node *t=Splayfromtop(t1,x);//要删除的已经变成根节点
if(t->val==x){
if(t->lson&&t->rson){node*l=t->lson;node*r=t->rson;free(t);
l=Findmax(l);l->rson=r;return l;}
else if(t->lson){node *l=t->lson;free(t);return l;}
else if(t->rson){node*r=t->rson;free(t);return r;}
else {free(t);t=NULL;return t;}
}
else {cout<<"not exist!"<<endl;return t;}
}
void splay_tree::Remove(eletype x){
root=Remove(root,x);
}
void splay_tree::Destroy(node *&t){
if(t==NULL)return;
Destroy(t->lson);Destroy(t->rson);free(t);
}
void splay_tree::Destroy(){
Destroy(root);
}
测试程序:
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include"Tree.h"
static int arr[]={
10,50,40,30,20,60};
using namespace std;
int main(){
int i;
//AVLtree<int>*tree=new AVLtree<int>();
splay_tree *tree=new splay_tree();
int len=sizeof(arr)/sizeof(int);
for(i=0;i<len;i++){;
tree->Insert(arr[i]);
}
tree->postorder();
tree->inorder();
i=30;
cout<<"Rotate at"<<" "<<i<<endl;
tree->Find(i);
tree->postorder();
tree->inorder();
tree->Destroy();
cout<<endl;
}
测试程序的主要流程是:新建伸展树,然后向伸展树中依次插入10,50,40,30,20,60。插入完毕这些数据之后,伸展树的节点是60;此时,再旋转节点,使得30成为根节点。依次插入10,50,40,30,20,60示意图如下:
Find(30) 后: