伸展树(splay)

在书上或者别人的博客上看的时候感觉还不是很明显,但是自己写出来并调试之后感觉真是十分的炫酷
特别是调试的时候,感觉这棵树就好像活的一样
(在不断的访问最后的一个节点的时候,能看到树的层数在不断的减少,直到理论的极限


(如果想知道一颗活的树是什么样的体验,可以自己调试一发
(这里窝为了方便直接用0~n-1作为树的元素,你也可以选择自己喜欢的一个方式
(因为只是第一份代码,所以还没有添加动态删除节点和动态添加节点这两个功能
(以后的可能还会优化图形界面和其它的一些功能
(如果有时间的话


(第一份代码写的比较复杂,不过既然已经调试出来了,还是先放在这里了
#include<bits/stdc++.h>
using namespace std;

struct node{
    int val;
    node *l,*r;
};

node *newnode(int x){
    node *ret = new node;
    ret->l=ret->r=NULL;
    ret->val = x;
    return ret;
}

void zig(node* &o){
    node *k = o->l;
    o->l = k->r;
    k->r = o;
    o = k;
}

void zag(node* &o){
    node *k = o->r;
    o->r = k->l;
    k->l = o;
    o = k;
}

void inser(int x,node *rot){
    if(rot->val > x){
        if(rot->l==NULL)
            rot->l = newnode(x);
        else
            inser(x,rot->l);
    }
    else{
        if(rot->r==NULL){
            rot->r = newnode(x);
        }
        else{
            inser(x,rot->r);
        }
    }
}

bool fndx(node *&rot,int x,int &d){
    if(rot->val == x){
        d = 0;
        return true;
    }
    else{
        int k;
        if(rot->val > x){    //to left
            if(rot->l == NULL || fndx(rot->l,x,k)==false)
                return false;
            else{
                if(k==0){
                    d = -1;
                    return true;
                }
                else{
                    if(k == -1){ // zig zig
                        zig(rot);zig(rot);
                    }
                    else{ // k=1, zag zig
                        zag(rot->l);zig(rot);
                    }
                    d = 0;
                    return true;
                }
            }
        }
        else{
            if(rot->r == NULL || fndx(rot->r,x,k)==false)
                return false;
            else{
                if(k==0){
                    d = 1;
                    return true;
                }
                else{
                    if(k == 1){ // zag zag
                        zag(rot);zag(rot);
                    }
                    else{ // zig zag
                        zig(rot->r);zag(rot);
                    }
                    d = 0;
                    return true;
                }
            }
        }
    }
}

bool fnd(node *&root,int x){
    int k;
    if(fndx(root,x,k)==false){
        return false;
    }
    else{
        if(k){
            if(k==1)
                zag(root);
            else
                zig(root);
        }
        return true;
    }
}


void out(node *s,int d,int k){
    if(s->l)
        out(s->l,d+1,-1);
    for(int i =0;i<d;i++)
        printf("   ");
    if(k!=0){
        printf(" ");
        if(k==1)
            printf("\\");
        else
            printf("/");
    }
    else{
        printf("-");
    }
    printf("%d\n",s->val);
    if(s->r)
        out(s->r,d+1,1);
}


int n =30;


int main(){
    node *root = newnode(0);
    for(int i = 1;i<n;i++){
        inser(i,root);
    }
    out(root,0,0);
    int x;
    while(~scanf("%d",&x)){
        printf("after find %d",x);
        puts("----------------");
        fnd(root,x);
        out(root,0,0);
    }
    return 0;
}



=============update==============

给出一些学习的建议吧

刚开始学的时候建议在纸上模拟几遍左旋和右旋的过程,最好能到想到zig或zag就可以在脑海里模拟出这个过程(

然后看双旋的时候也是

双旋到想到x在哪个方向能在纸上模拟出这个过程就可以了

然后就可以自己独立写一遍了,(这个时候会感觉自己写的十分复杂。。。就像我上面那个代码一样QAQ

再接着可以压缩自己的代码(提示:根据双旋的对称性)


以及下面是我优化过的代码

#include<bits/stdc++.h>
using namespace std;

#define l ch[0]
#define r ch[1]

struct node{
    int val;
    node *ch[2];
};

node *newnode(int x){
    node * ret = new node;
    ret->l=ret->r=NULL;
    ret->val = x;
    return ret;
}

void inser(node *rot,int x){
    int d = (rot->val > x)?0:1;
    if(rot->ch[d])
        inser(rot->ch[d],x);
    else
        rot->ch[d]=newnode(x);
}

void out(node *s,int d,int k){
    if(s->l)
        out(s->l,d+1,-1);
    for(int i =0;i<d;i++)
        printf("   ");
    if(k!=0){
        printf(" ");
        if(k==1)
            printf("\\");
        else
            printf("/");
    }
    else{
        printf("-");
    }
    printf("%d\n",s->val);
    if(s->r)
        out(s->r,d+1,1);
}

void print(node *s){
    puts("-----");
    out(s,0,0);
    puts("=====");
}

node *root = newnode(0);

void zg(node* &o,int d){
    node * k = o->ch[d];
    o->ch[d] = k->ch[1^d];
    k->ch[1^d] = o;
    o = k;
}

int splay(int x,node *& rot){
    if(!rot)
        return -1;
    if(rot->val == x)
        return 2;
    else{
        int d = rot->val > x?0:1;
        int k = splay(x,rot->ch[d]);
        if(k==2) return d;
        if(k==-1) return -1;
        if(k==d){
            zg(rot,k); zg(rot,k);
        }
        else{
            zg(rot->ch[d],k);
            zg(rot,d);
        }
        return 2;
    }
}

bool fnd(node* &root,int x){
    int k = splay(x,root);
    if(k==-1)
        return false;
    if(k!=2){
        zg(root,k);
    }
    return true;
}

int n =16;

int main(){
    for(int i = 1;i<n;i++){
        inser(root,i);
    }
    print(root);
    int x;
    while(~scanf("%d",&x)){
        if(x>=n){
            for(int i = 0;i<n;i++){
                fnd(root,i);
                print(root);
            }
            continue;
        }
        if(x < 0){
            for(int i =n-1;i>=0;i--){
                fnd(root,i);
                print(root);
            }
            continue;
        }
        printf("after find %d",x);
        fnd(root,x);
        print(root);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值