BST
ShelTeR_Pr1me · · 个人记录
Intro
BST 是二叉搜索树的简称,我们定义 BST 上每一个节点都有一个关键值,(就是点权好吧)。
BST 上每一个节点都满足以下性质:
- 该节点所有左子树的关键值都小于等于该节点的关键值。
- 该节点所有右子树的关键值都大于等于该节点的关键值。
实现
建立
出于避免越界,减少特殊判断的目的,我们一般会往 BST 里边丢一个负无穷的关键值和一个正无穷的关键值,仅有这两个节点组成的 BST 就是一颗空的 BST。
接下来我们假设 BST 里不会出现关键值相同的节点。
struct Bst {
int l, r; // 左子树右子树的下标
int val; // 关键值
}a[N];
int tot, rt;
int New(int val) {
a[++tot].val = val; // 把一个关键值插入
return tot; // 返回节点编号
}
void build() {
New(-INF); // 先插入负无穷
New(INF); // 再插入正无穷当负无穷的右子树
rt = 1, a[1].r = 2; // 根弄成 1,1 的后继下标当然是 2 咯
}
查找
在 BST 中查找是否存在关键值为
设变量
- 如果
p 的关键值等于val ,已经找到了。 - 如果
p 的关键值小于val ,如果p 的右子树为空说明不存在val ,否则就进去找val 。 - 如果
p 的关键值大于val ,如果p 的左子树为空说明不存在val ,否则就进去找val 。
int get(int p, int val) {
if(p == 0) return 0; // 都找不到了直接返回呗
if(val == a[p].val) return p; // 找到了就直接返回呗
return val < a[p].val ? get(a[p].l, val) : get(a[p].r, val); // 执行操作
}
插入
在 BST 中插入一个新值,和查找类似。找到要走向的
void insert(int &p, int val) {
if(p == 0) {
p = New(val);
return ;
}
if(val == a[p].val) return ;
if(val < a[p].val) ins(a[p].l, val);
else insert(a[p].r, val);
}
求前驱后继
先谈谈后继吧:
后继是指在 BST 中关键值大于
我们定义这个节点的编号为
- 没有找到
val ,这就说明val 的后继已经在经过的节点中更新过了,ans 即为所求。 - 找到了
val 的节点p ,如果p 没有右子树,说明你已经找到了,ans 即为所求。 - 好吧
p 它有右子树,没关系,我们进入右子树,然后向左子树跑,去找一个最贴近val 的值,然后这个val 对应的p 就是后继所在的节点。
int getnxt(int val) {
int ans = 2; // 我觉得吧,答案节点要从 2 开始防止判断边
int p = rt; // 从根开始找
while(p) {
if(val == a[p].val) { // 如果找到了 val
if(a[p].r > 0) { // 如果还有右子树
p = a[p].r; // 进入它的右子树,然后往左边跑去找更合适
while(a[p].l > 0) p = a[p].l; // 往左边跑
ans = p; // 更新下 ans
}
break;
}
if(a[p].val > val && a[p].val < a[ans].val) ans = p; // 沿途尝试更新 ans
p = val < a[p].val ? a[p].l : a[p].r;
}
return ans;
}
找前驱同理。
int getpre(int val) {
int ans = 1;
int p = rt;
while(p) {
if(val == a[p].val) {
if(a[p].l > 0) {
p = a[p].l;
while(a[p].r > 0) p = a[p].r;
ans = p;
}
break;
}
if(a[p].val < val && a[p].val > a[ans].val) ans = p;
p = val > a[p].val ? a[p].l : a[p].r;
}
return ans;
}
删除
删除关键值为
好吧,
void del(int &p, int val) {
if(p == 0) return ;
if(val == a[p].val) {
if(a[p].l == 0) p = a[p].r;
else if(a[p].r == 0) p = a[p].l;
else {
int nxt = a[p].r;
while(a[nxt].l > 0) nxt = a[nxt].l;
del(a[p].r, a[nxt].val);
a[nxt].l = a[p].l, a[nxt].r = a[p].r;
p = nxt;
}
return ;
}
if(val < a[p].val) del(a[p].l, val);
else del(a[p].r, val);
}
BST 的期望时间复杂度是 这样还能在 Hypixel 服务器里加上 5rp 值。
我们称这种左右子树差很大的 BST 是不平衡的,我们可以用一些奇妙的方法把它弄得平衡,怎么弄平衡呢?看下一篇博文吧。