您的位置:首页 > 其它

学习笔记 Treap

2013-10-13 09:32 204 查看
学习Treap之前先学的Splay,然后发现Treap真是太简单了,Greatwall1995神犇的意见要听啊

BST的缺陷是因为人为搞单调数据才爆的,随机数据还是logn的时间,Treap的思想也基于此,给每个添加的点赋一个随机优先值,然后整个树关于优先值是一个堆。

CLRS上要求读者证明插入节点后期望的旋转次数小于2,看到之后就吓呆了

接下来是具体实现,lrj的代码实在是太漂亮了,忍不住贴出来

const int maxn=1000;

double random(){ return (double)rand()/RAND_MAX;}
int random(int m) { return (int)((m-1)*random()+0.5);}
struct node{
node* ch[2];
int v,r,s;
node (int v=0):v(v) {ch[0]=ch[1]=NULL;s=1;r=random(maxn);}
int cmp(int x)const{
if (v==x)return -1;
return x<v?0:1;
}
void maintain(){
s=1;
if (ch[0]!=NULL)s+=ch[0]->s;
if (ch[1]!=NULL)s+=ch[1]->s;
}
};
node* root;
void rotate(node* & o,int d){
node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
o->maintain(); k->maintain(); o=k;
}

node* find1(node* o,int x){
if (o==NULL)return NULL;
if (o->v==x)return o;
return o->v<x? find1(o->ch[1],x):find1(o->ch[0],x);
}

void insert(node* &o,int x){
if (o==NULL){o=new node(x);}
else {
int d=o->cmp(x);
insert(o->ch[d],x);if (o->ch[d]->r>o->r)rotate(o,d^1);
}
o->maintain();
}

void remove(node* &o,int x){
int d=o->cmp(x);
if (d==-1){
node* u=o;
if (o->ch[0]!=NULL && o->ch[1]!=NULL){
int d2=(o->ch[0]->r)> (o->ch[1]->r)?1:0;
rotate(o,d2); remove(o->ch[d2],x);
}else{
if (o->ch[0]==NULL)o=o->ch[1];
else o=o->ch[0];
delete u;
}
}else remove(o->ch[d],x);
if (o!=NULL)o->maintain();
}
int rank(node* t,int key){
if (t==NULL)return 1;
if (key<=t->v)return rank(t->ch[0],key);
else return rank(t->ch[1],key)+1+ ( t->ch[0]==NULL?0:t->ch[0]->s );
}
int kth(node* o,int k){
int t= ( o->ch[0]==NULL? 0:o->ch[0]->s ) +1;
if (k==t)return o->v;
else if (k<t)return kth(o->ch[0],k);
else return kth(o->ch[1],k-t );
}

要注意:
1、这个代码较短,但常数较大

2、这个代码不能实现高效的prev和next操作

3、如果在Linux上交这个代码会CE,因为Linux不支持相同名字不同类型的两个函数

4、这个版本有个限制,不能出现重复数据,修改的话insert把cmp换掉即可

用这个Treap试了下营业额统计,和Splay不相上下,Treap的next和prev操作比Splay慢,否则的话貌似要比Splay快很多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: