treap的写法
(2012-05-10 16:41:13)
标签:
杂谈 |
treap有很多写法,今天研究了一下,觉得这种写法比较好(主要是代码比原来短多了):
如果是直接编的话,会比较烦,因为很多代码是对称的(对于旋转,插入,删除这些操作来说).
所以我们可以用0表示左,1表示右.那么son[0]是左儿子,son[1]是右儿子;Rotate(p,0)表示;左旋Rotate(p,1)表示右旋.
这样的话,很多对称的操作,都可以通过传递一个bool参数统一起来,就不用写两个对称的代码了.
定义:
struct Node
{
Node *son[2]; //用指针写会比较方便
int Key,w,Size;
//Key是关键字,w的随机生成的修正值,Size是子树大小
Node(int a,int b,int c,Node *d):Key(a),w(b),Size(c)
{
son[0]=son[1]=d;
}
}*__root,*null;
其中,__root是根结点,null是哨兵,空节点都指向哨兵.当然哨兵要初始化.
认真分析旋转,插入,删除操作之后会发现,哨兵的作用很大,很多判断都简化了.
其实可以加个优化,就是把重复的结点合并(在大多数题目上都可以这样做).
初始化:
void init()
{
null=new Node(-oo,oo,0,0); //这里维护的是小根堆
__root=null=null->son[0]=null->son[1]=null;
}
核心操作--旋转:
先来看看原始的左旋和右旋:
void Rotate_left(Node *&p)
{
Node *u=p->son[1];
p->son[1]=u->son[0];
u->son[0]=p;
u->Size=p->Size;
p->Size=p->son[0]->Size+p->son[1]->Size+1;
p=u;
}
void Rotate_right(Node *&p)
{
Node *u=p->son[0];
p->son[0]=u->son[1];
u->son[1]=p;
u->Size=p->Size;
p->Size=p->son[0]->Size+p->son[1]->Size+1;
p=u;
}
然后发现,它们的差异,只不过是前三句代码的下标而已.所以,果断用bool替代.
写inline会比较快:
inline void Rotate(Node *&p,bool b) //Rotate(p,0)表示;左旋Rotate(p,1)表示右旋
{
Node *u=p->son[!b];
p->son[!b]=u->son[b];
u->son[b]=p;
u->Size=p->Size;
p->Size=p->son[0]->Size+p->son[1]->Size+1;
p=u;
}
插入:
void Insert(Node *&p,const int &x) //注意引用
{
if (p==null) //如果找到了位置就插入
{
p=new Node(x,rand(),1,null);
return;
}
bool b=(x>p->Key);
//判断是往左子树还是右子树插入
Insert(p->son[b],x);
p->Size++; //维护Size
if
(p->son[b]->w<p->w)
Rotate(p,!b); //在左子树就右旋,在右子树就左旋
}
删除:
void Delete(Node *&p,const int &x)
{
if (p->son[0]==null
&&
p->son[1]==null)
{
p=null;//这里是等到目标结点变为叶子才删除,仅比常规的删除多做了一次旋转,但代码短多了
return;
}
bool b; //这里的b为if语句后的操作提供了便利
if (p->Key==x)
{
b=(p->son[1]->w>p->son[0]->w);
Rotate(p,b);
} else
b=(x>p->Key);
如果是直接编的话,会比较烦,因为很多代码是对称的(对于旋转,插入,删除这些操作来说).
所以我们可以用0表示左,1表示右.那么son[0]是左儿子,son[1]是右儿子;Rotate(p,0)表示;左旋Rotate(p,1)表示右旋.
这样的话,很多对称的操作,都可以通过传递一个bool参数统一起来,就不用写两个对称的代码了.
定义:
struct Node
{
}*__root,*null;
其中,__root是根结点,null是哨兵,空节点都指向哨兵.当然哨兵要初始化.
认真分析旋转,插入,删除操作之后会发现,哨兵的作用很大,很多判断都简化了.
其实可以加个优化,就是把重复的结点合并(在大多数题目上都可以这样做).
初始化:
void init()
{
核心操作--旋转:
先来看看原始的左旋和右旋:
void Rotate_left(Node *&p)
{
void Rotate_right(Node *&p)
{
然后发现,它们的差异,只不过是前三句代码的下标而已.所以,果断用bool替代.
写inline会比较快:
inline void Rotate(Node *&p,bool b)
{
插入:
void Insert(Node *&p,const int &x) //注意引用
{
删除:
void Delete(Node *&p,const int &x)
{

加载中…