zoukankan      html  css  js  c++  java
  • Splay 指针&&无父节点

        其实,代码还是99%的和 Running-coder 的相似,但是,没有但是……

        Splay在 NOIP && NOI 有一定地位,学一学,总比打暴搜强……

        Splay的功能有很多,百度一下,你就知道……

        Splay 中文名称 伸展树,是一种很666的平衡树,而平衡树就是优化的二叉搜索树,所以在二叉搜索树的基础上学习Splay会更好,然而我就直接跳过了二叉搜索树……

        

        代码:

        

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<string>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<ctime>
      8 #include<cstdlib>
      9 #include<cfloat>
     10 
     11 using namespace std;
     12 
     13 int MAX_INT=214746000;
     14 struct ez{
     15     int key;                         //key--当前节点的值
     16     int num;                         //num--当前节点值的数目
     17     int size;                        //size--当前节点的子节点个数
     18     ez *ch[2];                       //ch[0]--左孩子,ch[1]--右孩子。
     19     
     20     int cmp(int x){                  //比较函数,比较当前节点的值和要查询的值的大小
     21         if(x==key) return -1;                          
     22         else return x>key;
     23     }
     24     void maintain(){                 //maintain函数,用于计算每个节点的
     25         size=num;
     26         if(ch[0]!=NULL) size+=ch[0]->size;
     27         if(ch[1]!=NULL) size+=ch[1]->size;  //节点不为空,
     28     }
     29 };
     30 ez *root=NULL;                              //开始,根节点为空
     31 int f,x,n,u;
     32 
     33 void rotate(ez* &p,bool f){                 //旋转函数
     34     ez *t=p->ch[f^1];                                  
     35     if(p->ch[f^1]!=NULL)
     36     p->ch[f^1]=t->ch[f];
     37     t->ch[f]=p;                             //旋转过程,并不好描述,但只要背过代码,就完全没问题
     38     
     39     p->maintain();
     40     t->maintain();                          //处理size
     41     p=t;
     42 }
     43 
     44 void insert(ez* &p,int x){                   //插入函数
     45     if(p==NULL){                             //如果p指针为空指针,就新建一个指针
     46         p=(ez *)malloc(sizeof(ez));
     47         p->key=x;
     48         p->num=1;
     49         p->size=1;
     50         p->ch[0]=NULL;
     51         p->ch[1]=NULL;
     52         return;
     53     }else
     54     if(x==p->key){   //否则,如果当前指针的值与要插入的值相等,就将当前指针的num和size都加一
     55         p->size++;
     56         p->num++;
     57         return;
     58     }
     59     else
     60     if(x>p->key){  //否则继续寻找:若要查找的值比当前节点的值大就向右儿子查找,同时当前节点的子节点数目++
     61         insert(p->ch[1],x);
     62         p->size++;
     63         return;
     64     }
     65     else
     66     if(x<p->key){         //如果小,就向左儿子查找,当前子节点数目++
     67         insert(p->ch[0],x);
     68         p->size++;
     69         return;
     70     }
     71 }
     72 
     73 void del(ez* &p,int x){            //删除函数
     74     if(p==NULL) return;            //删除空节点,会 RE爆0,身败名裂!!!!
     75     if(p->key==x)                  //如果当前节点的值和要删除的值相同
     76     if(p->num>1){                  //如果该数的数目大于1,就num和size--就ok了。
     77         p->num--;
     78         p->size--;
     79         return;
     80     }
     81     else{                 //否则,把该节点旋转到一个叶子节点,这样就没有后顾之忧了,爆掉他!
     82         ez *t=p;
     83         if(p->ch[0]==NULL){
     84             p=p->ch[1];
     85             free(t);
     86             return;
     87         }else
     88         if(p->ch[1]==NULL){
     89             p=p->ch[0];
     90             free(t);
     91             return;
     92         }else{
     93             int o=rand()%1;
     94             rotate(p,o);
     95             del(p->ch[o],x);
     96             p->size--;
     97         }
     98         
     99     } 
    100     else{                   //寻找这个节点
    101         if(x<p->key) del(p->ch[0],x);
    102         else del(p->ch[1],x);
    103         p->size--;
    104     }
    105 }
    106 
    107 void splay(ez* &p,int x){ //没有这一部分的Splay就是一棵普通的二叉搜索树,拥有将某一点强行抽到根节点的能力
    108     int d1=p->cmp(x);                                
    109     if(d1==-1||p->ch[d1]==NULL) return;  //判断能否继续旋转
    110     int d2=p->ch[d1]->cmp(x);
    111     if(d2==-1||p->ch[d1]->ch[d2]==NULL){   //如果这能旋转一次,就旋转一次,否则 双旋
    112         rotate(p,d1^1);
    113         return;
    114     }else{
    115     splay(p->ch[d1]->ch[d2],x);           //判断能否在d1的基础上继续旋转
    116     if(d1==d2){
    117         rotate(p,d1^1);
    118         rotate(p,d2^1);
    119         return;
    120     }else{
    121         rotate(p->ch[d1],d2^1);
    122         rotate(p,d1^1);
    123         return;             //注意:不同的结果,旋转的方式不一样,如果实在理解不了,就背过代码就行了
    124     }
    125     }
    126 }
    127 
    128 int pre(int x){ //查前驱,方法:把要查的节点提到根节点,那么从他的左子树一直向右查询,得到的最终结果就是x的前驱,
    129     splay(root,x);
    130     if(root->key<x) return root->key;
    131     else{
    132         if(root->ch[0]==NULL) return -MAX_INT;
    133         else{
    134             splay(root->ch[0],MAX_INT);
    135             return root->ch[0]->key;
    136         }
    137     } 
    138 } 
    139 
    140 int succ(int x){               //查后继,方法恰好是求前驱反过来
    141     splay(root,x);
    142     if(root->key>x) return root->key;
    143     else{
    144         if(root->ch[1]==NULL) return -MAX_INT;
    145         else{
    146             splay(root->ch[1],-MAX_INT);
    147             return root->ch[1]->key;
    148         }
    149     }
    150 }
    151 
    152 int kth(ez* &p,int x){ //求第k小的数
    153     int s=0;  //方法:从根节点开始搜索,如果x比当前节点小就向左找,否则,名次上减去左子树的节点数,向右找。
    154     if(p->ch[0]!=NULL) s=p->ch[0]->size;
    155     if(x<=s) return kth(p->ch[0],x); else
    156     if(x<=s+p->num) return p->key;else
    157     return kth(p->ch[1],x-s-p->num);
    158 }
    159 
    160 int rank(int x){ //求当前点的排名
    161     splay(root,x);   //方法:从根节点搜索,如果在左边,就向左走,否则加上左边的节点数再向右找
    162     if(root->ch[0]==NULL) return 1;
    163     else return root->ch[0]->size+1;
    164 }
    165 
    166 int main(){
    167     srand(time(0)+20010930);
    168     
    169     scanf("%d",&n);
    170     for(int i=1;i<=n;i++){
    171         scanf("%d",&f);
    172         switch(f){
    173             case 1:{
    174                 scanf("%d",&x);
    175                 insert(root,x);
    176                 break;
    177             }
    178             case 2:{
    179                 scanf("%d",&x);
    180                 del(root,x);
    181                 splay(root,x);
    182                 break;
    183             }
    184             case 3:{
    185                 scanf("%d",&x);
    186                 printf("%d
    ",rank(x));
    187                 splay(root,x);
    188                 break;
    189             }
    190             case 4:{
    191                 scanf("%d",&x);
    192                 printf("%d
    ",kth(root,x));
    193                 splay(root,x);
    194                 break;
    195             }
    196             case 5:{
    197                 scanf("%d",&x);
    198                 printf("%d
    ",pre(x));
    199                 splay(root,x);
    200                 break;
    201             }
    202             case 6:{
    203                 scanf("%d",&x);
    204                 printf("%d
    ",succ(x));
    205                 splay(root,x);
    206                 break;
    207             }
    208         }
    209     }
    210 return 0; 211 }
  • 相关阅读:
    对话框
    枚举、联合
    WinCE 应用程序开机自启动方法
    调用directshow出现链接错误
    修改了WINCE自带的驱动程序后如何编译
    如何设置WINCE系统字体、字号?如何设置自己开发的软件的字体、字号
    在不采用硬件计时器的情况下如何创建更精确的计时器
    驱动程序如何发通知给应用程序
    如何得到WAV文件播放的总时间
    解决CE6和CE5在Platform Builder的Connectivity Options上的冲突
  • 原文地址:https://www.cnblogs.com/Misaki-Mei/p/7347957.html
Copyright © 2011-2022 走看看