zoukankan      html  css  js  c++  java
  • 一天一道算法题——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;
    }
  • 相关阅读:
    五大Java开源论坛
    mysql limit,offset 区别
    查询某个字段存在于哪几个表
    C++分享笔记:5X5单词字谜游戏设计
    Linux分享笔记:系统状态检测命令小结
    Linux分享笔记:查看帮助命令 & 常用系统工作命令
    数据结构(C语言)分享笔记:数据结构的逻辑层次、存储层次
    Linux分享笔记:shell终端的介绍
    Java开发学生管理系统
    JAVA使用JDBC连接,修改MySQL数据库(比较乱)
  • 原文地址:https://www.cnblogs.com/zyyz1126/p/12557454.html
Copyright © 2011-2022 走看看