二叉搜索树(BST)数组模拟支持左旋右旋求前驱后继

BST

给定一颗二叉树,树上的每个节点带有一个数值,称为节点的权,所谓的“BST性质”是指,对于树中任意一颗节点:

1. 该节点的权不小于它的左子树中任意节点的权;

2. 该节点的权不大于它的右子树中任意节点的权;

即:

val(lefttree) <= val(root) <= val(righttree) 

显然,二叉查找树的中序遍历是一个权值单增的序列,笔者曾天真的以为,同样的节点构成不同的BST,中序序列会因树的形状而改变。然实则非也!

然而,需要注意的是,为了避免越界,减少边界情况的判定,笔者一般在BST中额外的插入一个正无穷的权和一个负无穷的权,仅由这两个节点构成的BST是一颗初始的空BST:

在这里插入图片描述
下面请欣赏有注释的friendly的代码:

#include<bits/stdc++.h>
#define oo INT_MAX
#define maxn 50000
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define _for(i, a, b) for(int i = (a); i < (b) ;++i)
using namespace std;
struct bst
{
       int l, r;//左右子节点在数组中的下标
       int val;//权
}a[maxn];
int cnt, root;
int __new(int val) {
       a[++cnt].val = val;
       return cnt;
}
void __init__() {
       __new(-oo), __new(oo);
       root = 1, a[1].r = 2;
}
int __get(int p, int val) {//找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);
}
void __ins(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 __ins(a[p].r, val);
}
void __del(int val) {
       int& p = root;
       while (p)
       {
              if(val == a[p].val)break;
              p = val < a[p].val ? a[p].l : a[p].r;
       }
       if (p == 0)return;//did not find it
       if (a[p].l == 0) {//no left son
              p = a[p].r; //右子树代替
       }else if (a[p].r == 0) {// no right son
              p = a[p].l;
       } else {//having left son and right son,using the successive node
             int next = a[p].r;
              while(a[next].l > 0) next = a[next].l;
              __del(a[next].val);//此时a[next]没有左子树了
              a[next].l = a[p].l, a[next].r = a[p].r;
              p = next;
       }
}

 

int __nxt(int val) {//find the successive node
       int ans = 2; // a[2].val == oo
       int p = root;
       while(p) {
              if (a[p].val == val) {
                     if(a[p].r > 0) {//有右子树
                            p = a[p].r;
                            while(a[p].l > 0)p = a[p].l;
                            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;
}
int __pre(int val) {//find the precursor node
       int ans = 1; //a[1] == -oo
       int p = root;
       while(p)
       {
             if(a[p].val == 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 zig(int& p) {//右旋,clockwise
       int q = a[p].l;
       a[p].l = a[q].r, a[q].r = p;
       p = q;
}
void zag(int& p) {//左旋,anti-clockwise
       int q = a[p].r;
       a[p].r = a[q].l, a[q].l = p;
       p = q;
}

void _LDR_(int p) {
      if(a[p].l)_LDR_(a[p].l);
       cout << a[p].val << " ";
       if(a[p].r)_LDR_(a[p].r);
}
int main() {
       __init__();
       int num;
       while(cin >> num && num)__ins(root, num);
       _LDR_(root);
       system("pause");
}

其实朴素的BST有个致命的缺点–当给定的序列是严格升序或者是降序,那么BST就会退化成一条链,部分操作(查,删,增)将会退化成log(n)。

那么我们的前人为了避免这个问题,就发明了一种旋转方法,能改变树的结构,主要有两种操作:

zig&zag

在这里插入图片描述

the upper zig(4) to below

the under zag(2) to above

在这里插入图片描述

合理的操作会使bst变得平衡,如何才算是合理的操作呢?

我们前人发现了一种思想–随机化
由此衍生出treap:
我是传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值