zoukankan      html  css  js  c++  java
  • 《数据结构》C++代码 Splay

           Splay,伸展树。之所以先写这个课内并不怎么常用的数据结构,是因为本人非常喜欢Splay,我觉得这是非常有美感且灵活的一种平衡树。在此先声明,我的伸展树写法来源于CLJ大牛,基础好的同学可以去他的博客中看看他的Splay实现模板,我的实现仅仅借鉴了CLJ大神的一点实现技巧而已。我的博文《心中的大牛博客列表》中有CLJ大神的博客链接。

           还有很多同学可能并不了解Splay的思想,那么可以去看sqybi的文章《The magical splay》,百度文库就可以搜索到。这篇文章是我看过的里讲解splay最清晰的。里面的图和讲解都非常棒,里面的代码是Pascal的,但是没关系,只会C++的同学可以看我的代码。

           在此先要讲解一下CLJ大神的这个splay实现技巧:充分利用C/C++中将bool型的true和false的值设置为1和0的特点,将树的每个节点的左右孩子指针用如下方式定义——node *son[2]。如此一来,son[0]便是左孩子,son[1]便是右孩子。此时,便可以在实现中,将左侧、右侧操作的代码写成一段,利用一个bool型变量来区分就好了。因此,代码基本会少一半!

           我这么说大家肯定糊里糊涂的,不废话了,直接上代码,大家仔细看看代码就懂了。

    题目:sjtuoj 1221。

    清爽版:暂无。因为Splay的实现代码还是比较长的,因此并不考虑直接写,代码反而会很乱。

    类实现版:

      1 /*
      2  * 题目:sjtuoj 1221
      3  * oj链接:http://acm.sjtu.edu.cn/OnlineJudge
      4  */
      5 #include <iostream>
      6 #include <fstream>
      7 #include <string>
      8 #include <cstdio>
      9 using namespace std;
     10 
     11 const int minInt=1<<31;
     12 const int maxInt=minInt-1;
     13 
     14 struct dot
     15 {
     16     int c,num,size;
     17     dot *son[2],*up; // son[false]是左孩子,son[true]是右孩子,up是父亲
     18     
     19     dot(int value=0) { c=value; num=size=1; son[false]=son[true]=up=0; }
     20     bool get(dot *lr) { return son[true]==lr; }
     21     void add_up(int n) { for(dot *u=this;u;u=u->up) u->size+=n; }
     22     dot* born(bool k,dot* lr)
     23     {
     24         son[k]=lr;
     25         if(lr) { lr->up=this; add_up(lr->size); }
     26         return this;
     27     }
     28     dot* kill(bool k)
     29     {
     30         dot *lr=son[k]; son[k]=0;
     31         if(lr) { lr->up=0; add_up(-lr->size); }
     32         return lr;
     33     }
     34 };
     35 
     36 int vv(dot *u) { return u?u->c:0; }
     37 int nn(dot *u) { return u?u->num:0; }
     38 int ss(dot *u) { return u?u->size:0; }
     39 
     40 class Splay
     41 {
     42 public:
     43     dot *Root,*Min,*Max;
     44 private:
     45     void zg(dot *x)
     46     {
     47         dot *y=x->up,*z=y->up;
     48         bool i=(z?z->get(y):0),k=y->get(x); // 此处i==0时,i无意义
     49         
     50         if(z) z->kill(i);
     51         x->born(!k,y->born(k,y->kill(k)->kill(!k)));
     52         if(z) z->born(i,x);
     53         
     54         if(y==Root) Root=x; // 维护Root,可能也是保险?no!This is useful!
     55     }
     56     void splay(dot *x,dot *up=0) // 将x旋转到其父亲为up的位置
     57     {
     58         dot *y,*z;
     59         while(x->up!=up) // x还没到指定位置
     60         {
     61             y=x->up; if(y->up==up) { zg(x); break; } // 如果y是指定位置,则将x旋转到y
     62             z=y->up; zg((z->get(y)==y->get(x))?y:x); zg(x); // 将x旋转到z即可
     63         }
     64     }
     65     void recycle(dot *p)
     66     {
     67         if(!p) return;
     68         recycle(p->son[false]); recycle(p->son[true]);
     69         delete p;
     70     }
     71     dot* next(dot *p,bool k)
     72     {
     73         splay(p);
     74         
     75         dot *u=p->son[k];
     76         while(u->son[!k]) u=u->son[!k];
     77         return u;
     78     }
     79 public:
     80     Splay()
     81     {
     82         Min=Root=new dot(minInt); Max=new dot(maxInt);
     83         Min->born(true,Max);
     84     }
     85     int size() { return Root->size-2; }
     86     dot* Find(int c)
     87     {
     88         dot *u=Root;
     89         while(u&&u->c!=c) u=u->son[c>u->c];
     90         return u;
     91     }
     92     
     93     void Insert(int c)
     94     {
     95         bool k;
     96         dot *u=0,*v=Root;
     97         
     98         while(v&&v->c!=c)
     99         {
    100             u=v;
    101             k=(c>v->c);
    102             v=v->son[k];
    103         }
    104         if(v) { ++v->num; v->add_up(1); } else splay(u->born(k,new dot(c))->son[k]);
    105     }
    106     void Delete(int c)
    107     {
    108         dot *p=Find(c),*l,*r;
    109         
    110         --p->num; p->add_up(-1);
    111         if(p->num==0)
    112         {
    113             l=next(p,false); r=next(p,true);
    114             splay(l); splay(r,Root);
    115             recycle(r->kill(false));
    116         }
    117     }
    118     void Delete(int cl,int cr)
    119     {
    120         dot *L,*R,*l,*r;
    121         
    122         Insert(cl); Insert(cr);
    123         L=Find(cl); R=Find(cr);
    124         
    125         l=next(L,false); r=next(R,true);
    126         splay(l); splay(r,Root);
    127         recycle(r->kill(false));
    128     }
    129     int Find_ith(int i,dot *u) // 这里的三种情况,用到了其先后顺序,故顺序不能轻易改变
    130     {
    131         int size=ss(u->son[false]),mid=u->num;
    132         if(i<=size) return Find_ith(i,u->son[false]);
    133         if(i<=size+mid) return u->c;
    134         return Find_ith(i-size-mid,u->son[true]);
    135     }
    136 };
    137 
    138 Splay A; // 创建一棵Splay树,名叫A
    139 
    140 int main()
    141 {
    142     // 本题,假设题目数据均在 minInt+1 ~ maxInt-1 范围内
    143     int n,x,y; cin>>n;
    144     string order;
    145     for(int i=1;i<=n;++i)
    146     {
    147         cin>>order;
    148         if(order=="insert") { cin>>x; A.Insert(x); }
    149         if(order=="delete") { cin>>x; A.Delete(x); }
    150         if(order=="delete_less_than") { cin>>y; A.Delete(minInt+1,y-1); }
    151         if(order=="delete_greater_than") { cin>>x; A.Delete(x+1,maxInt-1); }
    152         if(order=="delete_interval") { cin>>x>>y; A.Delete(x+1,y-1); }
    153         if(order=="find") { cin>>x; cout<<(A.Find(x)?"Y":"N")<<endl; }
    154         if(order=="find_ith")
    155         {
    156             cin>>x;
    157             if(A.size()<x) { cout<<"N"<<endl; continue; }
    158             cout<<A.Find_ith(x+1,A.Root)<<endl; // 有一个Min,所以得找第x+1个
    159         }
    160     }
    161     
    162     return 0;
    163 }
  • 相关阅读:
    Centos 下查看服务器CPU的信息
    网速的一些知识整理
    如何复制文件夹里面的全部内容? 在pc上
    DataGridView中CellClick的使用,选中一行触发的动作可以在这个方法里执行
    C# 文件的压缩与解压缩
    C#调用Exe 及 有参数的
    oracle提示 ORA12154: TNS: 无法解析指定的连接标识符 OCIEnvCreate 失败, 返回代码为1,但错误消息文本不可用
    C# 导出wps配置服务器 注意事项
    C# FTP 操作类
    组件服务问题
  • 原文地址:https://www.cnblogs.com/icedream61/p/4141934.html
Copyright © 2011-2022 走看看