伸展树C++类实现<二>自顶向下设计

上一篇主要基于父节点形式的自底向上的设计实现伸展树,这一篇将实现基于左右辅助树的自顶向下的设计。

这种方式不需要节点存储其父节点的指针。当我们沿着树向下搜索某个节点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) 后:






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值