zoukankan      html  css  js  c++  java
  • 二叉搜索树

    Github Repo:https://github.com/sinkinben/DataStructure.git

    二叉搜索树(Binary Search Tree)定义:

    左子树的 Key 值不大于根的 Key 值,右子树的 Key 值不小于根的 Key 值。如果限制 Key 值是唯一的,那么就有:left.key < root.key < right.key

    性质:中序遍历所得序列呈升序(非降序)。

    本文实现 API:

    • selfCheck:检查当前的 BST 是否满足其性质。
    • search:根据关键字 val 查找某一节点。
    • insert:插入节点。
    • remove:删除节点
    • update:更新某一节点(实质是先删后加)。
    • maxval:BST 中的最大值。
    • minval:BST 中的最小值。
    • successor:查找某一节点的后继(即中序遍历中的下一个)。
    • precedessor:查找某一节点的先驱(即中序遍历的前一个)。

    selfCheck

    本函数用于 Debug,因此不考虑复杂度。

    先获取整个中序序列,检查是否为升序。

    void selfCheck()
    {
        auto v = this->inorder();
        int n = v.size();
        for (int i = 1; i < n; i++)
            assert(v[i] > v[i - 1]);
    }
    

    根据 BST 的性质,如果插入的 val 小于当前 x.val,则向左子树寻找,否则向右子树寻找。

    // search val by non-recursion
    TreeNode<T> *search(T val)
    {
        auto p = this->root;
        while (p != nullptr && p->val != val)
        {
            if (val < p->val)
                p = p->left;
            else
                p = p->right;
        }
        return p;
    }
    

    递归形式:

    // search val by recursion
    TreeNode<T> *innerSearch(TreeNode<T> *p, T val)
    {
        if (p == nullptr || p->val == val)
            return p;
        if (val < p->val)
            return innerSearch(p->left, val);
        else
            return innerSearch(p->right, val);
    }
    

    insert

    根据 BST 的性质,如果插入的 val 小于当前 x.val,则向左子树寻找插入位置,否则向右子树寻找。利用指针 y 记住 当前查找节点 x 的 parent,以方便后面的插入。

    // insert a new node into the BST, whose value is 'val'
    // each node in BST is unique
    // return nullptr means 'val' is already in BST
    TreeNode<T> *insert(T val)
    {
        if (this->root == nullptr)
            return this->root = new TreeNode<T>(val);
        auto x = this->root;
        auto y = x->parent; // nullptr actually
        while (x != nullptr)
        {
            y = x;
            if (val < x->val)
                x = x->left;
            else if (val > x->val)
                x = x->right;
            else
                return nullptr;
        }
        auto node = new TreeNode<T>(val);
        node->parent = y;
        return val < y->val ? (y->left = node) : (y->right = node);
    }
    

    remove

    首先实现一个移植函数 transplant ,该函数的作用是把子树 u 替换为子树 v 。即:

        p                       p
       /                      / 
      u   pr      ==>         v   pr
     /                      / 
    ul  ur                  vl  vr
    

    代码:

    // remove helper
    // replace subtree-u with subtree-v
    void transplant(TreeNode<T> *u, TreeNode<T> *v)
    {
        if (u == nullptr)
            return;
        // u is the root
        if (u->parent == nullptr)
            this->root = v;
        else if (u == u->parent->left)
            u->parent->left = v;
        else
            u->parent->right = v;
        if (v != nullptr)
            v->parent = u->parent;
    }
    

    根据删除节点 node 需要分情况讨论:

    image-20200921203659172

    图中的 z 就是下面所说的 node 。

    1. 没有左子树:直接用 node 的右子树替换 node ,右子树可以为 NULL 。如上图 (a) 。
    2. 只有左子树:用 node 的左子树替换 node。如上图 (b) 。
    3. 左右子树均有,那么用右子树的最小值 y (可以确定 y 没有左子树)替换 node,这时需要根据 y 是否为 node 的右孩子进行讨论:
      • y 是 node 的右孩子:如图 (c),直接 y 替换 node 。
      • y 不是 node 的右孩子:如图 (d),先使用 x 替换 y ,然后让 node 的右子树 r 成为 y 的右子树,最后使用变化后的 y 替换 node (该步骤与上一步相同)

    remove 代码:

    // remove node from the BST, whose value is 'val'
    bool remove(T val)
    {
        auto node = search(val);
        if (node == nullptr)
            return false;
        bool l = (node->left != nullptr);
        bool r = (node->right != nullptr);
        // case '!l' include (!l && !r) and (!l && r)
        if (!l)
            transplant(node, node->right);
        else if (l && !r)
            transplant(node, node->left);
        else
        {
            auto y = minval(node->right);
            if (y->parent != node)
            {
                transplant(y, y->right);
                y->right = node->right;
                y->right->parent = y;
            }
            transplant(node, y);
            y->left = node->left;
            y->left->parent = y;
        }
    
        delete node;
        return true;
    }
    

    update

    先删除后添加。

    // update oldval to newval if oldval is in the BST, otherwise do nothing
    TreeNode<T> *update(T oldval, T newval)
    {
        if (!remove(oldval))
            return nullptr;
        return insert(newval);
    }
    

    maxval/minval

    maxval 是位于 BST 最右端的孩子,minval 是最左端的孩子。

    // get max val in the BST
    TreeNode<T> *maxval(TreeNode<T> *p)
    {
        if (p == nullptr)
            return nullptr;
        while (p->right != nullptr)
            p = p->right;
        return p;
    }
    TreeNode<T> *maxval() { return maxval(this->root); }
    
    // get min val in the BST
    TreeNode<T> *minval(TreeNode<T> *p)
    {
        if (p == nullptr)
            return nullptr;
        while (p->left != nullptr)
            p = p->left;
        return p;
    }
    TreeNode<T> *minval() { return minval(this->root); }
    
    

    successor

    查找节点 x 的后继节点。

    如果 x 有右子树,那么 minval(x->right) 即为所求。

    如果没有,那么 x 的后继是最接近 x 的祖先,并且该祖先的左孩子也是 x 的祖先

    如图:

        19
       /  
      7    20
     / 
    6   8
         
          9
           
            10
           /
        ...
    

    上述二叉树的中序遍历为:6, 7, 8, 9, ..., 10, 19, 20 . 节点 10 的后继是 19 .

    /* get the node's successor, whose value is 'val'
         * if the right subtree of a node x in T is empty and x has a successor y, 
         * then y is the lowest ancestor of x whose left child is also an ancestor of x. 
         * (Recall that every node is its own ancestor.)
         */
    TreeNode<T> *successor(T val)
    {
        auto x = search(val);
        if (x == nullptr)
            return nullptr;
        if (x->right != nullptr)
            return minval(x->right);
        auto y = x->parent;
        while (y != nullptr && y->right == x)
            x = y, y = y->parent;
        return y;
    }
    

    precedessor

    与 successor 同理。

    // get the node's predecessor, whose value is 'val'
    TreeNode<T> *predecessor(T val)
    {
        auto x = search(val);
        if (x == nullptr)
            return nullptr;
        if (x->left != nullptr)
            return maxval(x->left);
        auto y = x->parent;
        while (y != nullptr && y->left == x)
            x = y, y = y->parent;
        return y;
    }
    
  • 相关阅读:
    App开放接口api安全性—Token签名sign的设计与实现
    查看文件(或文件夹)被哪个进程使用【文件已在另一程序中打开】
    利用递归将数组转码
    h5 定位
    使用OAuth Server PHP实现OAuth2服务
    在Linux上安装jdk,mysql,tomcat的准备工作
    Core Java笔记
    随机森林简介
    Linux 查看操作系统版本
    RNA_seq GATK 最佳实践
  • 原文地址:https://www.cnblogs.com/sinkinben/p/13708593.html
Copyright © 2011-2022 走看看