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的实现代码还是比较长的,因此并不考虑直接写,代码反而会很乱。

类实现版:

 /*
* 题目:sjtuoj 1221
* oj链接:http://acm.sjtu.edu.cn/OnlineJudge
*/
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
using namespace std; const int minInt=<<;
const int maxInt=minInt-; struct dot
{
int c,num,size;
dot *son[],*up; // son[false]是左孩子,son[true]是右孩子,up是父亲 dot(int value=) { c=value; num=size=; son[false]=son[true]=up=; }
bool get(dot *lr) { return son[true]==lr; }
void add_up(int n) { for(dot *u=this;u;u=u->up) u->size+=n; }
dot* born(bool k,dot* lr)
{
son[k]=lr;
if(lr) { lr->up=this; add_up(lr->size); }
return this;
}
dot* kill(bool k)
{
dot *lr=son[k]; son[k]=;
if(lr) { lr->up=; add_up(-lr->size); }
return lr;
}
}; int vv(dot *u) { return u?u->c:; }
int nn(dot *u) { return u?u->num:; }
int ss(dot *u) { return u?u->size:; } class Splay
{
public:
dot *Root,*Min,*Max;
private:
void zg(dot *x)
{
dot *y=x->up,*z=y->up;
bool i=(z?z->get(y):),k=y->get(x); // 此处i==0时,i无意义 if(z) z->kill(i);
x->born(!k,y->born(k,y->kill(k)->kill(!k)));
if(z) z->born(i,x); if(y==Root) Root=x; // 维护Root,可能也是保险?no!This is useful!
}
void splay(dot *x,dot *up=) // 将x旋转到其父亲为up的位置
{
dot *y,*z;
while(x->up!=up) // x还没到指定位置
{
y=x->up; if(y->up==up) { zg(x); break; } // 如果y是指定位置,则将x旋转到y
z=y->up; zg((z->get(y)==y->get(x))?y:x); zg(x); // 将x旋转到z即可
}
}
void recycle(dot *p)
{
if(!p) return;
recycle(p->son[false]); recycle(p->son[true]);
delete p;
}
dot* next(dot *p,bool k)
{
splay(p); dot *u=p->son[k];
while(u->son[!k]) u=u->son[!k];
return u;
}
public:
Splay()
{
Min=Root=new dot(minInt); Max=new dot(maxInt);
Min->born(true,Max);
}
int size() { return Root->size-; }
dot* Find(int c)
{
dot *u=Root;
while(u&&u->c!=c) u=u->son[c>u->c];
return u;
} void Insert(int c)
{
bool k;
dot *u=,*v=Root; while(v&&v->c!=c)
{
u=v;
k=(c>v->c);
v=v->son[k];
}
if(v) { ++v->num; v->add_up(); } else splay(u->born(k,new dot(c))->son[k]);
}
void Delete(int c)
{
dot *p=Find(c),*l,*r; --p->num; p->add_up(-);
if(p->num==)
{
l=next(p,false); r=next(p,true);
splay(l); splay(r,Root);
recycle(r->kill(false));
}
}
void Delete(int cl,int cr)
{
dot *L,*R,*l,*r; Insert(cl); Insert(cr);
L=Find(cl); R=Find(cr); l=next(L,false); r=next(R,true);
splay(l); splay(r,Root);
recycle(r->kill(false));
}
int Find_ith(int i,dot *u) // 这里的三种情况,用到了其先后顺序,故顺序不能轻易改变
{
int size=ss(u->son[false]),mid=u->num;
if(i<=size) return Find_ith(i,u->son[false]);
if(i<=size+mid) return u->c;
return Find_ith(i-size-mid,u->son[true]);
}
}; Splay A; // 创建一棵Splay树,名叫A int main()
{
// 本题,假设题目数据均在 minInt+1 ~ maxInt-1 范围内
int n,x,y; cin>>n;
string order;
for(int i=;i<=n;++i)
{
cin>>order;
if(order=="insert") { cin>>x; A.Insert(x); }
if(order=="delete") { cin>>x; A.Delete(x); }
if(order=="delete_less_than") { cin>>y; A.Delete(minInt+,y-); }
if(order=="delete_greater_than") { cin>>x; A.Delete(x+,maxInt-); }
if(order=="delete_interval") { cin>>x>>y; A.Delete(x+,y-); }
if(order=="find") { cin>>x; cout<<(A.Find(x)?"Y":"N")<<endl; }
if(order=="find_ith")
{
cin>>x;
if(A.size()<x) { cout<<"N"<<endl; continue; }
cout<<A.Find_ith(x+,A.Root)<<endl; // 有一个Min,所以得找第x+1个
}
} return ;
}

《数据结构》C++代码 Splay的更多相关文章

  1. 【数据结构】平衡树splay和fhq—treap

    1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...

  2. [数据结构]伸展树(Splay)

    #0.0 写在前面 Splay(伸展树)是较为重要的一种平衡树,理解起来也依旧很容易,但是细节是真的多QnQ,学一次忘一次,还是得用博客加深一下理解( #1.0 Splay! #1.1 基本构架 Sp ...

  3. codeforces733D. Kostya the Sculptor 偏序cmp排序,数据结构hash,代码简化

    对于n==100.1,1,2或者1,2,2大量重复的形状相同的数据,cmp函数最后一项如果表达式带等于,整个程序就会崩溃 还没有仔细分析std::sort的调用过程,所以这里不是很懂..,mark以后 ...

  4. 【算法与数据结构专场】BitMap算法基本操作代码实现

    上篇我们讲了BitMap是如何对数据进行存储的,没看过的可以看一下[算法与数据结构专场]BitMap算法介绍 这篇我们来讲一下BitMap这个数据结构的代码实现. 回顾下数据的存储原理 一个二进制位对 ...

  5. 《数据结构》C++代码 前言

    现在大二正在上<数据结构>课,课内的书上代码实现很喜欢无脑用类.变量名字很长,而且常常实现太繁琐,并且代码有些无法运行,这些对于老手无所谓,但初学者看起来却会很不舒服.因此写点自己实现这些 ...

  6. C++基础代码--20余种数据结构和算法的实现

    C++基础代码--20余种数据结构和算法的实现 过年了,闲来无事,翻阅起以前写的代码,无意间找到了大学时写的一套C++工具集,主要是关于数据结构和算法.以及语言层面的工具类.过去好几年了,现在几乎已经 ...

  7. python算法与数据结构-二叉树的代码实现(46)

    一.二叉树回忆 上一篇我们对数据结构中常用的树做了介绍,本篇博客主要以二叉树为例,讲解一下树的数据结构和代码实现.回顾二叉树:二叉树是每个节点最多有两个子树的树结构.通常子树被称作“左子树”(left ...

  8. bzoj1588: [HNOI2002]营业额统计 splay瞎写

    最近各种瞎写数论题,感觉需要回顾一下数据结构 写一发splay冷静一下(手速过慢,以后要多练练) 用splay是最直接的方法,但我感觉离散一波应该可以做出来(没仔细想过) 现在没有很追求代码优美,感觉 ...

  9. 文艺平衡树 Splay 学习笔记(1)

    (这里是Splay基础操作,reserve什么的会在下一篇里面讲) 好久之前就说要学Splay了,结果苟到现在才学习. 可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构. ...

随机推荐

  1. WINCC runtime连接SIMOTION simulator SIMOSIM

    测试使用的软件版本 TIA Portal V14sp1 Windows7 sp1 (professional) Scout 5.1(integrated in TIA 集成项目) VMware wor ...

  2. mysql主从分离

    1.工具: 两台机器 master:192.168.0.1 slave:192.168.0.2 2.master的配置 找到mysql的配置文件,一般centos的是/etc/my.cnf,ubunt ...

  3. IOS NSURLConnection(大文件下载)

    NSURL:请求地址 NSURLRequest:一个NSURLRequest对象就代表一个请求,它包含的信息有 一个NSURL对象 请求方法.请求头.请求体 请求超时 … … NSMutableURL ...

  4. HDU 3639 Hawk-and-Chicken(强连通分量+缩点)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u013480600/article/details/32140501 HDU 3639 Hawk-a ...

  5. Linux---who命令学习

    who命令 获取正在登录系统的用户 使用Linux的who命令 第一个参数book代表用户名,第二个参数tty7代表终端名,第三个参数代表时间,第四个参数代表用户的登录地址. 阅读手册 使用命令读手册 ...

  6. CDH4.5.0下安装lzo

    参考 http://www.cloudera.com/content/cloudera-content/cloudera-docs/Impala/1.0.1/Installing-and-Using- ...

  7. Linux驱动学习(编写一个最简单的模块)

    在Linux中想做驱动开发,那么一定要先熟悉module的使用和编写 一.什么是module 从名字上看就是模块的意思,我个人的理解就是一个一个的小程序,可以进行动态的安装和卸载,而在这里面就实现一些 ...

  8. Excel文档数据转成Plist文件

    有时候我们需要导入大量数据到App中静态数据,但数据又是存在Excel中,怎么办? 第一,复制数据粘贴到一个.txt文本文档中 第二,就是撸代码了 比如,我需要导入的数据表有2列字段,name和bar ...

  9. [转]C++ explicit的作用

    explicit作用: 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. explicit使用注意事项: * e ...

  10. VS2013使用自带的数据库 Microsoft SQL Server 2012 Express LocalDB

    注:DeptLocalDB:自己取的数据库实例名称 DeptSharedLocalDB:自己取的实例共享名称np:\\.\pipe\LOCALDB#SH7C6ED5\tsql\query:命名管道名称 ...