非旋转Treap
非旋转Treap
通过节点的优先级来维护树的平衡, 下面是普通非旋转Treap (弱平衡,
性质
- Treap是笛卡尔树的一种,只是 节点优先级是随机的
- $Tree+Heap$: 二叉搜索树+堆的性质
- 2个核心操作 分裂+合并
分裂 split
按照 节点权值分裂或者值的排名分裂
$split_val$
将一颗
treap
分裂成2个treap
,第一个treap
所有节点的权值$\le key$ , 第二个treap
所有节点的权值$\gt key$
判断节点权值$val[index]$ 是否 $\le key$,
- 若$val[index]\le key$,则第一个$treap$就是 $index$及其左子树, 但右子树可能还有节点权值$\le key$,所以再去$index$的右子树去分裂
- 若$val[index] \gt key$,则第二个$treap$就是$index$及其右子树.但左子树可能还有节点权值$\gt key$ ,所以再去$index$左子树去分裂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// oi-wiki 上的指针版
pair<node *, node *> split(node *u, int key) {
if (u == nullptr) {
return make_pair(nullptr, nullptr);
}
if (key < u->key) {
pair<node *, node *> o = split(u->lch, key);
u->lch = o.second;
return make_pair(o.first, u);
} else {
pair<node *, node *> o = split(u->rch, key);
u->rch = o.first;
return make_pair(u, o.second);
}
}$split_kth$
和$split_val$一样, 注意一下去了右子树减去前面所有排名
合并 merge
合并2个$treap$是有顺序的,子树$x$的中序遍历
3,5,7
,子树$y$的中序遍历1,4,8
,那么合并$(x,y)$后$treap$的中序遍历为3,5,7,1,4,8
, 将$y$树代表的序列拼接到$x$树代表的序列为了保持平衡, 根据节点的优先级来合并
例如$merge(x,y)$,判断节点的优先级$priority$
- $priority[x] < priority[y]$ ,那么$x$作为根节点,$y$和$x$的右子树去合并 (因为$y$要接在$x$序列后面,根据中序遍历的性质,所有要去$x$的右子树)
- $priority[x] \ge priority[y]$,那么$y$作为根节点, $x$和$y$的左子树去合并,(因为中序遍历的性质,去$y$的左子树)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// oi-wiki 指针版
node *merge(node *u, node *v) {
if (u == nullptr) {
return v;
}
if (v == nullptr) {
return u;
}
if (u->priority > v->priority) {
u->rch = merge(u->rch, v);
return u;
} else {
v->lch = merge(u, v->lch);
return v;
}
}
其他操作 (都是基于分裂和合并)
- 建树(
我现在只会一个一个插入) - $insert(val) = split_val + new_node + merge$
- $delete(val) = split_val + split_kth + merge$
- $rank(val) = split_val + merge$
- $kth(k) = split_kth*2 + merge$
- $pre(val) = split_val + split_kth + merge$
- $nxt(val) = split_val + split_kth +merge$
1 |
|
%%%% 大佬非旋Treap
杂: 1天+1早上
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!