Treap(树堆)
/ / 阅读耗时 9 分钟 本文是Splay(伸展树)的后续。
在介绍Splay时,已经提及了BST的概念。BST在最坏情况下会达到$O(n)$复杂度,于是有各种使其平衡的方法,Treap就是一种,它也属于平衡树,比Splay要更易实现。
Splay是通过伸展操作来使树的结构随机化,以达到均摊$O(logn)$的复杂度。Treap是通过在维护BST时同时维护堆来实现结构的随机化。
所谓Treap就是Tree+Heap,故称树堆。
先来看看Treap的结点结构体定义,和Splay类似:1
2
3
4
5
6
7struct Node {
int v{}, key{}, ch[2]{}, s, num;
Node() : num(0), s(0) {
ch[0] = ch[1] = 0;
}
} node[100005];
没记录父结点?是的,在Treap中不需要记录父结点信息。
另外还可以发现多了一个key,key记录这个结点的优先级。刚才已经提到,Treap是树与堆的结合(这里的堆不再是完全二叉树,只要有堆的性质即可),所谓堆的性质就是:所有结点的优先级不得小于其子结点优先级。这当然是大根堆,用小根堆也是可以的,本文中使用大根堆。我们在维护BST的同时还要满足堆的要求。
key应该如何赋值?在插入一个新结点时,会给它分配一个随机的优先值,这个可以通过rand()函数来实现。从这里就可以看出Treap的原理:通过优先级的随机性来保持树结构的随机性。
下面的函数,若无特殊说明,函数都采用与Splay中相同的命名。
旋转操作
Treap中同样有旋转操作。当某结点不满足堆的性质时(比如它的优先级大于父结点),就需要进行一次旋转,将其旋转到父结点的位置。
Treap中只有左旋和右旋,没有Splay中双旋的概念。1
2
3
4void rotate(int &x, int w) {
int c1 = node[x].ch[w], c2 = node[c1].ch[w ^ 1];
node[x].ch[w] = c2, node[c1].ch[w ^ 1] = x, node[c1].num = node[x].num, update(x), x = c1;
}
上面就是旋转函数的定义,它的作用是将编号为x的结点旋转下去,方向为w(1为左旋),这和splay中的旋转上去有所不同。但事实上将子结点旋转上去就是把父结点旋转下来。
这里有一些值得注意的细节。一处是node[c1].num = node[x].num,这其实就是update(c1)的简略写法。另外还有x=c1,这里巧妙地使用引用来实现我们在Splay中旋转的第三步。
插入操作
Treap中的插入是基于递归的,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17void insert(int &x, int v) {
if (!x) {//空结点,新建结点
x = cnt++;
node[x].v = v, node[x].s = 1, node[x].num = 1, node[x].key = rand();
node[x].ch[0] = node[x].ch[1] = 0;
return;
}
node[x].num++;//路过的结点都要更新num
if (node[x].v == v)node[x].s++;//找到直接更新s
else if (node[x].v < v) {//找右树
insert(node[x].ch[1], v);
if (node[node[x].ch[1]].key > node[x].key)rotate(x, 1);//旋转,维护堆的性质
} else {//找左树
insert(node[x].ch[0], v);
if (node[node[x].ch[0]].key > node[x].key)rotate(x, 0);
}
}
它的作用是在以结点x为根的子树上插入值为v的结点。
当x为0时,说明这里是一个空结点,此时新建结点,更新信息,分配优先级。
另外,所有经过的结点都需要更新num。其次在递归回溯后需要检查堆的性质是否满足,如果不满足就需要旋转来调整。从这里可以看出引用的技巧性。
删除操作
1 | void del(int &x, int v) { |
Treap的删除操作基于分类讨论,有这几种情况(只考虑完全删除的情况,s自减一不考虑):
- 若该结点没有儿子,直接删除
- 若结点仅有右儿子,则左儿子代替其位置。仅有左儿子同理。
- 若结点有两个儿子,则将优先级大的一个旋转到该结点位置,再递归进行删除。
这里的一个易错点是每一个经过的结点需要更新num,但是上面的分类讨论中不需要更新,因为上面的分类讨论过程只是更改了一下树的结构。
其余的操作与Splay完全相同。