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++));
}
}
}
首先看如何插入结点,树形结构上递归的代码总是最好写的:
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++));
}
}
}
相关文章推荐
- Treap小解析(Part 1 of 2)
- Anatomy of an Elasticsearch Cluster part.1——深度解析ElasticSearch(1)
- 解读Tomcat(三):请求处理解析Part_1
- Learning a Part of C++(for ACM/ICPC) (7) STL中的string和bitset
- Android:New Google Maps Android API now part of Google Play services
- new JSONObject(str)无法解析 报错:org.json.JSONException: Value of type java.lang.String cannot be converted to JSONObject
- 2007:Part Number System of a USA networking company
- The development and prosperous of deep learning theory applying in computer vision(Image part)
- [77] The pursuit of Happiness-Part 1-One Day at a Time
- EXPLORING THE WORLD OF ANDROID :: PART 2
- 关于MD5算法报错的解决This implementation is not part of the Windows Platform FIPS validated cryptographic
- Long Paths in .NET, Part 2 of 3 [Kim Hamilton][译]
- iOS-Core Bluetooth Overview(API Reference) of the second part
- The Building Blocks- Components of EA Part 2- Process, People, Network and Time
- comp.unix.aix faq -Part 4 of 5
- A 'Brief' History of Neural Nets and Deep Learning, Part 1
- MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)
- Windows Store apps开发[43]C++/CX Part 4 of [n]: Static Member Functions
- php解析xml提示Invalid byte 1 of 1-byte UTF-8 sequence错误的处理方法
- Operator Overloading part 1(Chapter 12 of Thinking in C++)