BST总结
Posted hlw1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BST总结相关的知识,希望对你有一定的参考价值。
BST 是 Treap 的基础。
只写一点基本操作方便自己理解。
性质:左儿子 < 自己 < 右儿子
上图
插入
根据性质,比当前结点小就插入左子树,大就插入右子树,相等直接令当前结点的 cnt++ 即可。
void insert(int o, int k) {//在当前结点 o 插入 k 值
tr[o].sz++;
if (tr[o].val == k) {
tr[o].cnt++;
return;
}
if (v < tr[o].val) {
if (tr[o].ls != 0) insert(tr[o].ls, k);
else {
tot++;
tr[tot].val = k, tr[tot].sz = tr[tot].cnt = 1;
tr[o].ls = tot;
}
}
else {
if (tr[o].rs != 0) insert(tr[o].rs, k);
else {
tot++;
tr[tot].val = k, tr[tot].sz = tr[tot].cnt = 1;
tr[o].rs = tot;
}
}
删除
直接找到该数字所在的结点,令 cnt-- 就好了。
代码就不写了
因为上面那位大佬没写
前驱
一个数的前驱是指小于这个数的最大的数。
如果当前结点的值大于这个数,直接递归进左子树中找,小于的话就递归进右子树中找。
int pre(int o, int k, int ans) {
if (tr[o].val >= k) {
if (!tr[o].ls) return ans;
else return pre(tr[o].ls, k, ans);
}
else {
if (!tr[o].rs) {
if (tr[o].val < k) return tr[o].val;//必须小于这个数
else return ans;
}
else if (tr[o].cnt) return pre(tr[o].rs, k, tr[o].val);//注意此时当前结点的值一定小于 ans ,要更新 ans
else return pre(tr[o].rs, k, ans);
}
}
后继
和前驱的方法是一样的。
int suf(int o, int k, int ans) {
if (tr[o].val <= k) {
if (!tr[o].rs) return ans;
else return suf(tr[o].rs, k, ans);
}
else {
if (!tr[o].ls) {
if (tr[o].val > k) return tr[o].val;
else return ans;
}
else if (tr[o].cnt) return suf(tr[o].ls, k, tr[o].val);
else return suf(tr[o].ls, k, ans);
}
}
排名
当前结点的排名为它的左子树大小加上自己的 cnt ,如果小于要找的排名,就递归进右子树,并更新排名,否则先查找是否是当前结点,不是再去左子树。
int GetRank(int o, int rk) {
if (!o) return INF;
if (tr[tr[o].ls].sz >= rk) return GetRank(tr[o].ls, rk);
else if (tr[tr[o].ls].sz + tr[o].cnt >= rk) return tr[o].val;
return GetRank(tr[o].rs, rk - tr[tr[o].ls].sz - tr[o].cnt);
}
找值
如果当前结点的值小于查询的值,就在右子树找,同时排名要加上当前结点左子树的大小和当前结点的 cnt 值,否则直接递归进左子树找。
int GetVal(int o, int k) {
if (!o) return 0;
if (tr[o].val == k) return tr[tr[o].ls].sz + 1;
else if (tr[o].val > k) return GetVal(tr[o].ls, k);
return GetVal(tr[o].rs, k) + tr[tr[o].ls].sz + tr[o].cnt;
}
以上是关于BST总结的主要内容,如果未能解决你的问题,请参考以下文章