• P5076 【深基16.例7】普通二叉树(简化版)题解


    题目传送门

    一、数组+lower_bound+upper_bound模拟

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 10010;
    int a[N];
    int q, cmd, number, cnt;
    long long p;
    
    //解法1:暴力(使用二分优化查询)
    //lower_bound(begin,end,number)函数是求begin-end中(排好序)第一个大于等于 number的数
    //upper_bound(begin,end,number)函数是求begin-end中(排好序)第一个大于 number的数
    int main() {
        //q次询问
        cin >> q;
        while (q--) {
            cin >> cmd; //1-5共5个命令
            switch (cmd) {
                case 1:
                    cin >> number;
                    cout << lower_bound(a + 1, a + cnt + 1, number) - a << endl;
                    break;
                case 2:
                    cin >> number;
                    cout << a[number] << endl;
                    break;
                case 3:
                    cin >> number;
                    p = lower_bound(a + 1, a + cnt + 1, number) - a;
                    if (p == 1) cout << -2147483647 << endl;
                    else cout << a[p - 1] << endl;
                    break;
                case 4:
                    cin >> number;
                    p = upper_bound(a + 1, a + cnt + 1, number) - a;
                    if (p == cnt + 1) cout << 2147483647 << endl;
                    else cout << a[p] << endl;
                    break;
                case 5:
                    cin >> number;
                    a[++cnt] = number;
                    sort(a + 1, a + cnt + 1);
                    break;
            }
        }
        return 0;
    }
    

    二、BST二叉搜索树

    #include <bits/stdc++.h>
    
    using namespace std;
    
    //题解
    //https://www.cnblogs.com/do-while-true/p/13566274.html
    //const int INF = 2147483647;  这个 2147483647的十六进制表示:0x7fffffff,是等价的
    const int INF = 0x7fffffff;
    const int N = 1000010;
    int cnt;
    struct Node {
        int left;   //左儿子
        int right;  //右儿子
        int size;   //以该节点为根结点的子树的结点个数
        int value;  //该结点的权值
        int num;    //该结点权值出现的次数
    } tree[N];
    int q, opt, x;
    /**
    * 测试用例:
    7
    5 1
    5 3
    5 5
    1 3
    2 2
    3 3
    4 3
    
    参考答案:
    2
    3
    1
    5
     */
    //查询数x的排名(找出以root为根的树中,有多少个结点值小于查询数x)
    int queryVal(int root, int x) {
        //root==0表示进入到一个结点,准备再向下,结果再向下没有了,就是:表示找不到权值为x的数,返回0
        if (root == 0) return 0;
    
        //如果x等于树根的value值,那么比它小的有tree[tree[root].left].size个,
        // 它是第tree[tree[root].left].size+1个
        if (x == tree[root].value) return tree[tree[root].left].size;
    
        //如果x小于树根的value值,那么需要到左子树中去计算排名
        if (x < tree[root].value) return queryVal(tree[root].left, x);
    
        //如果x大于树根的value值,那么需要到右子树中去计算排名,同时,需要加上左子树的
        // 结点个数+root的结点个数
        return queryVal(tree[root].right, x) + tree[tree[root].left].size + tree[root].num;
    }
    
    //查询排名为x的数
    int queryRank(int root, int x) {
        //root==0表示进入到一个结点,准备再向下,结果再向下没有了,就是:表示找不到排名为x的数,返回0
        if (root == 0) return 0;//其实这里的有坑的,找不到题目没有说明是返回INF,还是返回0,
        // 实测返回INF也是可以AC的。
    
        //如果左子树中包含这个排名,那么递归到左子树去找
        if (tree[tree[root].left].size >= x) return queryRank(tree[root].left, x);
        //如果根结点的排名==x,那么返回根结点的权值
        if (tree[tree[root].left].size + tree[root].num >= x) return tree[root].value;
        //如果右子树中包含这个排名,那么递归到右子树中去找,这个子排名就是减去左子树的总结点个数
        // 再减去root的个数
        return queryRank(tree[root].right, x - tree[tree[root].left].size - tree[root].num);
    }
    
    //向二叉搜索树中增加一个权值为x的数字
    void insert(int root, int x) {
        //由于增加了一个结点,root的总结点个数+1
        //这一步是递归的必要步骤,表示以它为根的家族中增加了一个结点
        tree[root].size++;
    
        //如果新增加的数字x与root根的权值相等,那么num++
        if (tree[root].value == x) {
            tree[root].num++;
        } else if (tree[root].value > x) {//如果root的权值大于x,左子树
            //如果左子树不空,则递归向左子树插入结点x
            if (tree[root].left != 0) insert(tree[root].left, x);
            else {
                //如果左子树为空,那么需要创建一个新结点
                tree[++cnt].value = x; //新的数组位置用来存储x
                tree[cnt].size = 1;    //新增加的结点,下面没有子树,所以size=1
                tree[cnt].num = 1;     //权值为x的目前只有1个
                tree[root].left = cnt; //添加为左子树
            }
        } else { //如果root的权值小于x,右子树
            //如果右子树不空,则递归向右子树插入结点x
            if (tree[root].right != 0) insert(tree[root].right, x);
            else {
                //如果右子树为空,那么需要创建一个新结点
                tree[++cnt].value = x;          //新的数组位置用来存储x
                tree[cnt].size = 1;             //新增加的结点,下面没有子树,所以size=1
                tree[cnt].num = 1;              //权值为x的目前只有1个
                tree[root].right = cnt;         //添加为右子树
            }
        }
    }
    
    /**
     * 功能:查询前驱
     * @param root 以root为根的树
     * @param x    要查找的数字x
     * @param ans  暂存的前驱值,待更新成最合理的前驱值
     * @return     数字x的前驱
     */
    int queryPrev(int root, int x, int ans) {
        //如果根结点值大于x,那么需要去左子树中去找
        if (tree[root].value >= x) {
            //如果左子树为空的,将前面获取到的最优解返回就可以了
            if (tree[root].left == 0) return ans;
            else
                //到左子树中去查找
                return queryPrev(tree[root].left, x, ans);
        } else {
            //如果根结点值小于x,那么需要到右子树中去找
            //如果右子树为空,那么就是根结点的value值
            if (tree[root].right == 0) return tree[root].value;
            //右子树不为空,递归到右子树去查找
            return queryPrev(tree[root].right, x, tree[root].value);
        }
    }
    
    /**
     * 功能:查询后继
     * @param root 以root为根的树
     * @param x    要查找的数字x
     * @param ans  暂存的后继值,待更新成最合理的后继值
     * @return     数字x的后继
     */
    int queryNext(int root, int x, int ans) {
        //如果根结点的权值小于等于x,需要向右子树去找
        if (tree[root].value <= x) {
            //如果右子树为空,则没有比它更大的,返回暂存的最合理值ans
            if (tree[root].right == 0) return ans;
            else
                //如果右子树不空,则递归到右子树中去找
                return queryNext(tree[root].right, x, ans);
        } else {
            //向左子树中去找
    
            //如果左子树为空,那么就是根的value值
            if (tree[root].left == 0) return tree[root].value;
            //如果左子树不空,递归到左子树去找
            return queryNext(tree[root].left, x, tree[root].value);
        }
    }
    
    
    int main() {
        //q次询问
        cin >> q;
        while (q--) {
            //操作命令和操作的值
            cin >> opt >> x;
            switch (opt) {
                case 1: //查询x数的排名,注意这后面的+1,其实,rnk就是在根为root的子树中,
                // 找到比x值小的结点的个数,然后再加1,就是x的排名
                    cout << queryVal(1, x) + 1 << endl;
                    break;
                case 2: //查询排名为x的数
                    cout << queryRank(1, x) << endl;
                    break;
                case 3: //求x的前驱
                    cout << queryPrev(1, x, -INF) << endl;
                    break;
                case 4: //求x的后继
                    cout << queryNext(1, x, INF) << endl;
                    break;
                case 5: //插入一个数 x
                    if (cnt == 0) {                 //一个都没有,那么,第一个是根结点
                        cnt++;                      //数组中1号位置
                        tree[cnt].num = 1;          //权值是x的数量目前是1个
                        tree[cnt].size = 1;         //它+子树结点的总结点个数是1个
                        tree[cnt].value = x;        //权值是x
                    } else insert(1, x);       //将数x插入到根为1的二叉搜索树中
                    break;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Android由一个activity 间隔5秒自动跳转到另外一个activity
    ZXing二维码的生成和解析
    JAVA生成条形码
    JAVA生成带Logo的二维码
    JAVA操作MongoDB数据库
    MongoDB数据库的简介及安装
    Redis在windows下的安装使用
    class关键字
    遍历器接口
    Promise对象
  • 原文地址:https://www.cnblogs.com/littlehb/p/15089615.html
Copyright © 2020-2023  润新知