一天一道算法题——BST二叉查找树

题目描述

您需要写一种数据结构,来维护一些数( 都是 10^9 以内的数字)的集合,最开始时集合是空的。其中需要提供以下操作,操作次数 q 不超过 10^4

  1. 查询 x 数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,因输出最小的排名)。
  2. 查询排名为 x的数。
  3. 求 x 的前驱(前驱定义为小于 x,且最大的数)。
  4. 求 x 的后继(后继定义为大于 x,且最小的数)。
  5. 插入一个数 x

输入输出样例

输入
  7
5 1
5 3
5 5
1 3
2 2
3 3
4 3
输出 
2
3
1
5

什么是二叉树?

每个结点最多有两个子结点,分别称为左孩子,右孩子,以他们为根的树称为左子树,右子树。

1 struct node{
2   int val;
3   node* l,r;      
4 };

什么是BST(Binary Search Tree)?

(1)每个元素有唯一的键值。这些键值能比较大小。

(2)任意一个结点的键值比它的左子树的任意结点大,右子树的任意结点小。

所以我们使用中序遍历就可以得到BST的有序排列。

 如图就是一个BST。

BST的基本操作有:插入,查询,删除。

根据题意,我们只需要实现插入,和查询的操作。

题目有些东西没讲清楚,比如:

(1)查询x数的排名时 x可能不在树上

(2)没有前驱输出-0X7fffffff

(3)没有后继输出 0X7fffffff

指针实现的变种BST(有多个相同键值,后来插入的相同键值被安插在了第一个相同键值的左子树上)代码:

#include<bits/stdc++.h>
using namespace std;

//使用BST,二叉搜索树
struct node {
    node *l, *r;
    int v,lsum,rsum;
    node(int val):v(val),lsum(0),rsum(0),l(0),r(0){}
} *root;

void insert(node*& now,int x) {//*&表示在函数里面对now的值进行改变,那么在调用函数时传入的参数的指针值也会改变
    if (!now) {
        now = new node(x);
        return;
    }
    if (now->v <= x)
        insert(now->r, x),now->rsum++;
    else
        insert(now->l, x), now->lsum++;
}

int find_rank(node* now,int x,int k) {
    if(!now) return k;
    if (now->v == x)return k + now->lsum + 1;
    if (now->v < x)return find_rank(now->r, x, k + now->lsum+1);
    return find_rank(now->l, x, k);
}

int find_num(node* now,int x) {
    if (!now)return 2147483647;
    int tmp = now->lsum + 1;
    if (tmp == x)return now->v;
    if (tmp < x)return find_num(now->r, x - tmp);
    return find_num(now->l, x);
}

int prev_num(int x) {
    node* p = root;
    int c=-2147483647;
    while (p) {
        if (x > (p->v)) {
            c = p->v;
            p = p->r;
        }
        else {
            p = p->l;
        }
    }
    return c;
}

int next_num(int x) {
    node* p = root;
    int c = 2147483647;
    while (p) {
        if (x < (p->v)) {
            c = p->v;
            p = p->l;
        }
        else {
            p = p->r;
        }
    }
    return c;
}

int main() {
    int n,a,b;
    cin >> n;
    while (n--) {
        cin >> a >> b;
        switch (a) {
        case 5:insert(root,b); break;
        case 1:cout<<find_rank(root,b,0)<<endl; break;
        case 2:cout<<find_num(root,b)<<endl; break;
        case 3:cout << prev_num(b) << endl; break;
        case 4:cout << next_num(b) << endl; break;
        }
    }
    return 0;
}

(这个过样例的时候是可以的,但在提交的时候莫名其妙要把cout<<find_rank(root,b,0)<<endl;改为cout<<find_rank(root,b,0)+1<<endl;,然后样例就过不了了,结果AC了。呕血~)

然后是数组实现代码。

#include<iostream>
#include<cstdio>
using namespace std;
const int INF=0x7fffffff;
int cont;
struct node{
    int val,ls,rs,cnt,siz;
}tree[500010];
int n,opt,xx;
void add(int x,int v)
{
    tree[x].siz++;
    if(tree[x].val==v){
        tree[x].cnt++;
        return ;
    }
    if(tree[x].val>v){
        if(tree[x].ls!=0)
          add(tree[x].ls,v);
        else{
            cont++;
            tree[cont].val=v;
            tree[cont].siz=tree[cont].cnt=1;
            tree[x].ls=cont;
        }
    }
    else{
        if(tree[x].rs!=0)
          add(tree[x].rs,v);
        else{
            cont++;
            tree[cont].val=v;
            tree[cont].siz=tree[cont].cnt=1;
            tree[x].rs=cont;
        }
    }
}
int queryfr(int x, int val, int ans) {
    if (tree[x].val>=val)
    {
        if (tree[x].ls==0)
            return ans;
        else
            queryfr(tree[x].ls,val,ans);
    }
    else
    {
        if (tree[x].rs==0)
            return (tree[x].val<val) ? tree[x].val : ans;
        if (tree[x].cnt!=0)
            return queryfr(tree[x].rs,val,tree[x].val);
        else
            return queryfr(tree[x].rs,val,ans);
    }
}
int queryne(int x, int val, int ans) {
    if (tree[x].val<=val)
    {
        if (tree[x].rs==0)
            return ans;
        else
            queryne(tree[x].rs,val,ans);
    }
    else
    {
        if (tree[x].ls==0)
            return (tree[x].val>val)? tree[x].val : ans;
        if (tree[x].cnt!=0)
            return queryne(tree[x].ls,val,tree[x].val);
        else
            return queryne(tree[x].ls,val,ans);
    }
}
int queryrk(int x,int rk)
{
    if(x==0) return INF;  
    if(tree[tree[x].ls].siz>=rk)   
        return queryrk(tree[x].ls,rk); 
    if(tree[tree[x].ls].siz+tree[x].cnt>=rk)   
        return tree[x].val; 
    return queryrk(tree[x].rs,rk-tree[tree[x].ls].siz-tree[x].cnt);
}
int queryval(int x,int val)
{
    if(x==0) return 0; 
    if(val==tree[x].val) return tree[tree[x].ls].siz+1; 
    if(val<tree[x].val) return queryval(tree[x].ls,val);
    return queryval(tree[x].rs,val)+tree[tree[x].ls].siz+tree[x].cnt;
}
inline int read()
{
    int r=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        r=(r<<3)+(r<<1)+(ch^48);
        ch=getchar();
    }
    return r*w;
}
int main()
{
    n=read();
    while(n--){
        opt=read();xx=read();
        if(opt==1) printf("%d
",queryval(1,xx)+1);
        else if(opt==2) printf("%d
",queryrk(1,xx));
        else if(opt==3) printf("%d
",queryfr(1,xx,-INF));
        else if(opt==4) printf("%d
",queryne(1,xx,INF));
        else{
            if(cont==0){
                cont++;
                tree[cont].cnt=tree[cont].siz=1;
                tree[cont].val=xx;
            }
            else add(1,xx);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zyyz1126/p/12557454.html