您的位置:首页 > 其它

Treap小解析(Part 2 of 2)

2014-04-30 00:12 330 查看
上文中我们熟悉了treap的旋转操作,接下来可以开始正文的书写了。

首先看如何插入结点,树形结构上递归的代码总是最好写的:

void Insert(node *&t, int x)
{
if(t == nul)
{
t = new node(x, nul);
return;
}
bool d = x >= t->val; // 比t->val大就插右边,否则插左边
Insert(t->ch[d], x);
if(t->ch[d]->pri < t->pri) // 插入的那个结点的优先级大于根节点就旋转,默认数字小的优先级大,下同
rot(t, d);
else
t->calsize();
}注意到上面判断往左插还是往右插的代码是:bool d = x >= t->val;
这里的区别就是存不存在重复数据,重复只算一次的话就这样写:if(t->val == x)return;

还有一个就是t = new node(x, nul);注意到这里用了个nul变量而不是NULL空指针,这是一个很好的优化,将会在删除函数中有所体现。

接着我们来看看如何删除结点。

删除节点也需要旋转,将待删除结点转到叶子结点上,然后干掉就行了。



删除的时候会碰到5种情况:



如果我们将空节点设置为NULL的话就如上图所示,那么在删除的时候就要考虑以上5种情况。

如果左右孩子都为空,那么删除自身

如果左孩子为空,将右孩子旋转上来,再删除自身

如果右孩子为空,将左孩子旋转上来,再删除自身

如果左右都不空,就将优先级大的旋转上来,再递归删除

相信上面的判断已经足够写出一长串语句了,非常麻烦。既然如此我们为何不将NULL结点的优先级设为inf,即无穷大呢,这样一来,删除语句就能大大简化了。

为了使得原本NULL的结点拥有优先级,我们需要增设一个nul变量。

node *nul = new node(0, NULL);

nul->size = 0;

nul->pri = inf;

然后应该是NULL的结点都指向这个结点就行了。

void Delete(node *&t, int x)
{
if(t == nul) return;
if(t->val == x)
{
bool d = t->ch[1]->pri < t->ch[0]->pri;
if(t->ch[d] == nul) // 两个孩子结点都是nul,那么直接删除根节点就行了
{
delete t;
t = nul;
return;
}
rot(t, d); // 将优先级高的旋转上去
Delete(t->ch[!d], x);
}
else
{
bool d = x > t->val;
Delete(t->ch[d], x);
}
t->calsize();
}接下来就可以放上完整代码了,以下是POJ1442的代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<ctime>
using namespace std;

#define inf 0x3f3f3f3

struct node
{
int val; // 值
int pri; // 优先级
int size;// 树的大小(左子树数量+右子树数量+1(自身))
node *ch[2];
node(int v, node *n):val(v) // 初始化结点
{
ch[0] = ch[1] = n;
pri = rand();
size = 1;
}
void calsize() // 计算树的大小
{
size = ch[0]->size + ch[1]->size + 1;
}
};

int num[30010];

node *root, *nul;

void rot(node *&t, bool d) // 将ch[d]旋转上去
{
node *r = t->ch[d];
t->ch[d] = r->ch[!d];
r->ch[!d] = t;
t->calsize();
r->calsize();
t = r;
}

void Insert(node *&t, int x) // 插入一个结点
{
if(t == nul)
{
t = new node(x, nul);
return;
}
bool d = x >= t->val;
Insert(t->ch[d], x);
if(t->ch[d]->pri < t->pri)
rot(t, d);
else
t->calsize();
}

int iTh(node *t, int x) // 寻找树中第i小的数
{
if(t == nul)return -1;
int r = t->ch[0]->size;
if(r+1 == x)return t->val;
if(r+1 > x)
return iTh(t->ch[0], x);
return iTh(t->ch[1], x-r-1);
}

int main()
{
srand(unsigned(time(0)));
int n, m;
nul = new node(0, NULL);
nul->pri = inf;
nul->size = 0;
root = nul;
int cnt = 0, rank = 1, op;
while(~scanf("%d%d", &n, &m))
{
for(int i = 0; i < n; i++)
scanf("%d", &num[i]);
for(int i = 0; i < m; i++)
{
scanf("%d", &op);
while(op > cnt)
{
Insert(root, num[cnt++]);
}
printf("%d\n",Query(root, rank++));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: