精华内容
下载资源
问答
  • 二叉搜索树C++代码

    2016-07-30 19:33:48
    本文主要讨论二叉搜索树的基本性质以及基本操作,并用C++代码实现,每个成员操作以成员函数的形式出现,并附有适当的说明。 包括: 普通二叉树的遍历(先序,中序,后序,分层),二叉搜索树的建立,插值,删值,求...
  • 相信大部分人都会实现二叉搜索树,实际上就是根据与当前节点相比的大与小进行整个树的建立。这里部分代码引用的是王争老师的二叉搜索树代码,为了方便关于二叉搜索树其他内容的讲解,代码基本上具有注释,如果哪里写...

    相信大部分人都会实现二叉搜索树,实际上就是根据与当前节点相比的大与小进行整个树的建立。这里部分代码引用的是刘雨波老师的二叉搜索树代码,为了方便关于二叉搜索树其他内容的讲解,代码基本上具有注释,如果哪里写的不明白可以留言,因为我自己也修改了一下,不知道是否存在bug。

    具体的功能有:

    下面针对常用功能进行讲解,由于搜索,删除以及插入元素的实现方法很简单,这里就不进行讲解了,具体的文字叙述在博文数据结构与算法之二叉查找树精简要点总结中已有提到,同时遍历方法在博文二叉搜索树的深度&广度优先遍历 C++实现中已经讲解了。

    最大(小)值获取与删除

    实际上由于二叉树的特性,由于中序遍历便是从小到大的排序,所以最大值和最小值均位于二叉树的最左端和最右端的叶子节点。这样我们只需要对一个节点进行操作,很简单就不多讲了。
    在这里插入图片描述

    获取ceil值

    ceil值指的是大于所查找元素的全部元素中的最小元素,实现方法是保存搜索路径中最新的大于元素的值。下面进行该实现方法的分析。

    搜索过程中当前节点的元素值与所查找元素一共有四种情况:

    1. 当前节点元素小于所查找的元素,并且当前节点是父节点的右子节点

    父 节 点 元 素 值 < 当 前 节 点 元 素 值 < 所 查 找 元 素 值 父节点元素值 < 当前节点元素值 < 所查找元素值 <<

    由于当前节点元素小于所查找元素,而我们需要的是大于等于所查找元素的节点,所以无需考虑当前节点。由于当前节点是父节点的右子节点,所以其大于父节点,所以父节点也小于所查找节点值。所以无需操作。

    2. 当前节点元素小于所查找的元素,并且当前节点是父节点的左子节点

    当 前 节 点 元 素 值 < 所 查 找 元 素 值 < 父 节 点 元 素 值 当前节点元素值 < 所查找元素值 < 父节点元素值 <<

    由于当前节点元素小于所查找元素,而我们需要的是大于等于所查找元素的节点,所以无需考虑当前节点。由于当前节点是父节点的左子节点,所以其小于父节点,所以父节点也大于所查找节点值。这时由于根据情况3,4已经保存了父节点的元素值。

    3. 当前节点元素大于所查找的元素,并且当前节点是父节点的右子节点

    父 节 点 元 素 值 < 所 查 找 元 素 值 < 当 前 节 点 元 素 值 父节点元素值 < 所查找元素值 < 当前节点元素值 <<

    由于当前节点元素大于所查找元素,所以保存当前节点的元素值。由于当前节点是父节点的右子节点,所以其大于父节点,所以所查找节点位于父节点的右子树,及所查找元素也大于父节点。所以这时应该保存当前节点元素值。

    4. 当前节点元素大于所查找的元素,并且当前节点是父节点的左子节点

    所 查 找 元 素 值 < 当 前 节 点 元 素 值 < 父 节 点 元 素 值 所查找元素值 < 当前节点元素值 < 父节点元素值 <<

    由于当前节点元素大于所查找元素,所以保存当前节点的元素值。由于当前节点是父节点的左子节点,所以其小于父节点,所以所查找节点位于父节点的左子树,及所查找元素也小于父节点。所以这时应该保存父节点元素值。

    不知道看到这里读者是否已经看懂了这个实现方法的可行性,但是有一点没有考虑到,就是说不在搜索路径中的节点是否也可能是ceil值呢,现在我们再来分析一下,实际情况也分为两种:

    1. 当前节点元素大于所查找的元素
    这时下一步将进行,即左子树的查找,同时由于当前元素值大于所查找的元素值,所以当前元素值的小于于右子树的全部节点元素值。所以有以下的关系式。

    所 查 找 元 素 值 < 当 前 节 点 元 素 值 < 右 子 树 全 部 节 点 元 素 值 所查找元素值 < 当前节点元素值 < 右子树全部节点元素值 <<

    所以右子树不需要遍历。

    2. 当前节点元素小于所查找的元素
    这时下一步将进行,即右子树的查找,同时由于当前元素值大于所查找的元素值,所以当前元素值的大于左子树的全部节点元素值。所以左子树也不需要遍历

    所以可以看出每次我们保存的都是搜索路径中的最新大于所查找元素的节点元素值(有点绕,多担待😁),同时我们保证每一个搜索到的元素都按照这样的步骤进行操作便可以实现ceil元素的获取了,可见我们的实现方法是正确的

    代码实现如下

    Key ceil(Key key) {
        return ceil(root, key);
    }
    
    Key ceil(Node *node, Key key) {
        Node *ceilNode = nullptr;
        while (true) {
            if (node == nullptr)
                break;
            if (key == node->key)
                break;
            else if (key < node->key) {
                ceilNode = node;
                node = node->left;
            } else {
                node = node->right;
            }
        }
        return ceilNode == nullptr ? -1 : ceilNode->key;
    }
    

    获取floor值

    floor值指的是小于所查找元素的全部元素中的最大元素,实现方法是保存搜索路径中最新的小于元素的值。下面进行该实现方法的分析。

    搜索过程中当前节点的元素值与所查找元素一共有也四种情况:

    • 当前节点元素小于所查找的元素,并且当前元素是父节点的右子节点
    • 当前节点元素小于所查找的元素,并且当前元素是父节点的左子节点
    • 当前节点元素大于所查找的元素,并且当前元素是父节点的右子节点
    • 当前节点元素大于所查找的元素,并且当前元素是父节点的左子节点

    由于这四种情况与ceil值获取原理类似便不再讲解。

    代码实现如下

    Key floor(Key key) {
        return floor(root, key);
    }
    
    Key floor(Node *node, Key key) {
        Node *floorNode = nullptr;
        while (true) {
            if (node == nullptr)
                break;
            if (key == node->key)
                break;
            else if (key < node->key) {
                node = node->left;
            } else {
                floorNode = node;
                node = node->right;
            }
        }
        return floorNode == nullptr ? -1 : floorNode->key;
    }
    
    

    查找排名第n的元素

    对于正在刷题的同学,肯定做过获取第n个元素这个算法,是通过中序遍历获取的,这里提供另一种思路,在二叉树中为每一个节点添加count变量,存储当前节点下全部节点的个数(包括本身)。如下图所示:
    在这里插入图片描述
    通过维护该树中所含元素的个数count可以求得,其与查找元素相似,在查找过程中,令当大于当前节点元素时,执行rank -= 该节点左子树的节点个数+1,当rank=该节点左子树的节点个数+1时,当前节点为所求节点;

    实际上这分为三种情况,我来简单分析一下:

    1. 当前节点左子节点的Count(左子树的节点数)大于当前的Rank值 - 1

    由于左子树的Count值大于当前的Rank值 - 1,所以左子树包含的元素多于Rank值 - 1,而当前值大于左子树所有节点,即当前值的排名大于Rank,所以应该想左子树搜索。

    2. 当前节点左子节点的Count(左子树的节点数)小于当前的Rank值 - 1

    由于左子树的Count值小于当前的Rank值 - 1,所以左子树包含的元素小于Rank值 - 1,而当前值大于左子树所有节点,即当前值的排名小于Rank,所以应该向右子树搜索。

    3. 当前节点左子节点的Count(左子树的节点数)等于当前的Rank值 - 1

    由于左子树的Count值小于当前的Rank值 - 1,所以左子树包含的元素等于Rank值 - 1,而当前值大于左子树所有节点,即当前值的排名等于Rank,所以当前节点为所需节点。

    代码实现如下

    Value *select(int rank) {
        return select(root, rank);
    }
    Value *select(Node *node, int rank) {
        if (rank <= 0)
            return nullptr;
        while (true) {
            if (node == nullptr)
                return nullptr;
            if (rank == (node->left != nullptr ? node->left->count + 1 : 1))
                return &node->value;
            else {
                if (rank < (node->left != nullptr ? node->left->count + 1 : 1)) {
                    node = node->left;
                } else {
                    rank -= (node->left != nullptr ? node->left->count + 1 : 1);
                    node = node->right;
                }
            }
        }
    }
    

    查找元素的排名rank

    通过维护该树中所含元素的个数n可以求得,其与查找元素相似,在查找过程中,令当大于等于当前节点元素时执行 rank += 该节点左子树的节点个数+1,即可求得rank;因为如果是搜索右子树时,则在原来的rank基础上又增加了左子树全部节点的个数。这里的分析和查找排名第n的元素类似,便不详细展开了。

    代码实现如下

    int rank(Key key) {
        return rank(root, key);
    }
    
    int rank(Node *node, Key key) {
        int _rank = 0;
        while (true) {
            if (node == nullptr)
                return -1;
            if (key == node->key) {
                _rank += node->right != nullptr ? node->count - node->right->count : node->count;
                return _rank;
            } else {
                if (key < node->key) {
                    node = node->left;
                } else {
                    _rank += node->right != nullptr ? node->count - node->right->count : node->count;
                    node = node->right;
                }
            }
        }
    }
    

    二叉树的完整代码

    template<typename Key, typename Value>
    class binarySearchTree {
    private:
        struct Node {
            Key key;
            Value value;
            int count;
            Node *left;
            Node *right;
    
            Node(Key key, Value value) {
                this->key = key;
                this->value = value;
                this->count = 1;
                this->left = this->right = nullptr;
            }
    
            Node(Node *node) {
                this->key = node->key;
                this->value = node->value;
                this->count = node->count;
                this->left = node->left;
                this->right = node->right;
            }
        };
    
        Node *root;
        int count;
    
    public:
        binarySearchTree() {
            root = nullptr;
            count = 0;
        }
    
        ~binarySearchTree() {
            destroy(root);
            assert(count == 0);
        }
    
        // 返回二叉树的元素个数
        int size() {
            return count;
        }
    
        // 返回二叉树是否为空
        int isEmpty() {
            return count == 0;
        }
    
        // 插入节点
        void insert(Key key, Value value) {
            if (!this->contain(key)) {
                if (root == nullptr) {
                    root = new Node(key, value);
                    count++;
                    return;
                }
                root->count++;
                insert(root, key, value);
            }
        }
    
        // 检查二叉树是否包含键值为key的元素
        bool contain(Key key) {
            return contain(root, key);
        }
    
        // 在二叉树中寻找键值为key的value值
        Value *search(Key key) {
            return search(root, key);
        }
    
        // 前序遍历
        void preOrder() {
            preOrder(root);
        }
    
        // 中序遍历
        void inOrder() {
            inOrder(root);
        }
    
        // 后序遍历
        void postOrder() {
            postOrder(root);
        }
    
        // 层序遍历
        void levelOrder() {
            std::queue<Node *> q;
            q.push(root);
            while (!q.empty()) {
                Node *node = q.front();
                q.pop();
                std::cout << node->key << " ";
                if (node->left)
                    q.push(node->left);
                if (node->right)
                    q.push(node->right);
            }
        }
    
        // 寻找最小的键值
        Key minimum() {
            assert(count != 0);
            Node *minNode = minimum(root);
            return minNode->key;
        }
    
        // 寻找最大的键值
        Key maximum() {
            assert(count != 0);
            Node *maxNode = maximum(root);
            return maxNode->key;
        }
    
        // 从二叉树中删除最小值所在节点
        void removeMin() {
            if (root)
                root = removeMin(root);
        }
    
        // 从二叉树中删除最大值所在节点
        void removeMax() {
            if (root)
                root = removeMax(root);
        }
    
        // 从二叉树中删除键值为key的节点
        void remove(Key key) {
            root = remove(root, key);
        }
    
        Key floor(Key key) {
            return floor(root, key);
        }
    
        Key ceil(Key key) {
            return ceil(root, key);
        }
    
        int rank(Key key) {
            return rank(root, key);
        }
    
        int getCount(Key key) {
            return getCount(root, key);
        }
    
        Value *select(int rank) {
            return select(root, rank);
        }
    
    
    private:
    
        // 在以node为根的二叉搜索树中查找key所对应的value
        Value *search(Node *node, Key key) {
            while (true) {
                if (node == nullptr)
                    return nullptr;
                if (key == node->key)
                    return &(node->value);
                else if (key < node->key)
                    node = node->left;
                else
                    node = node->right;
            }
        }
    
        Key floor(Node *node, Key key) {
            Node *floorNode = nullptr;
            while (true) {
                if (node == nullptr)
                    break;
                if (key == node->key)
                    break;
                else if (key < node->key) {
                    node = node->left;
                } else {
                    floorNode = node;
                    node = node->right;
                }
            }
            return floorNode == nullptr ? -1 : floorNode->key;
        }
    
        Key ceil(Node *node, Key key) {
            Node *ceilNode = nullptr;
            while (true) {
                if (node == nullptr)
                    break;
                if (key == node->key)
                    break;
                else if (key < node->key) {
                    ceilNode = node;
                    node = node->left;
                } else {
                    node = node->right;
                }
            }
            return ceilNode == nullptr ? -1 : ceilNode->key;
        }
    
        int rank(Node *node, Key key) {
            int _rank = 0;
            while (true) {
                if (node == nullptr)
                    return -1;
                if (key == node->key) {
                    _rank += node->right != nullptr ? node->count - node->right->count : node->count;
                    return _rank;
                } else {
                    if (key < node->key) {
                        node = node->left;
                    } else {
                        _rank += node->right != nullptr ? node->count - node->right->count : node->count;
                        node = node->right;
                    }
                }
            }
        }
    
    
        Value *select(Node *node, int rank) {
            if (rank <= 0)
                return nullptr;
            while (true) {
                if (node == nullptr)
                    return nullptr;
                if (rank == (node->left != nullptr ? node->left->count + 1 : 1))
                    return &node->value;
                else {
                    if (rank < (node->left != nullptr ? node->left->count + 1 : 1)) {
                        node = node->left;
                    } else {
                        rank -= (node->left != nullptr ? node->left->count + 1 : 1);
                        node = node->right;
                    }
                }
            }
        }
    
        // 向以node为根的二叉搜索树中,插入节点(key, value)
        // 返回插入新节点后的二叉搜索树的根
        void insert(Node *node, Key key, Value value) {
            while (true) {
                if (key == node->key) {
                    node->value = value;
                    return;
                } else {
                    if (key < node->key) {
                        if (node->left != nullptr) {
                            node = node->left;
                            node->count += 1;
                        } else {
                            node->left = new Node(key, value);
                            count++;
                            return;
                        }
                    } else {// key > node->key
                        if (node->right != nullptr) {
                            node = node->right;
                            node->count += 1;
                        } else {
                            node->right = new Node(key, value);
                            count++;
                            return;
                        }
                    }
                }
            }
        }
    
        // 查看以node为根的二叉搜索树中是否包含键值为key的节点
        bool contain(Node *node, Key key) {
            while (true) {
                if (node == nullptr)
                    return false;
                if (key == node->key)
                    return true;
                else if (key < node->key)
                    node = node->left;
                else
                    node = node->right;
            }
        }
    
        // 查看以node为根的二叉搜索树中key节点的count
        int getCount(Node *node, Key key) {
            while (true) {
                if (node == nullptr)
                    return -1;
                if (key == node->key)
                    return node->count;
                else if (key < node->key)
                    node = node->left;
                else
                    node = node->right;
            }
        }
    
        // 对以node为根的二叉搜索树进行前序遍历
        void preOrder(Node *node) {
    
            if (node != nullptr) {
                std::cout << node->key << " ";
                preOrder(node->left);
                preOrder(node->right);
            }
        }
    
        // 对以node为根的二叉搜索树进行中序遍历
        void inOrder(Node *node) {
    
            if (node != nullptr) {
                inOrder(node->left);
                std::cout << node->key << " ";
                inOrder(node->right);
            }
        }
    
        // 对以node为根的二叉搜索树进行后序遍历
        void postOrder(Node *node) {
    
            if (node != nullptr) {
                postOrder(node->left);
                postOrder(node->right);
                std::cout << node->key << " ";
            }
        }
    
        void destroy(Node *node) {
            if (node != nullptr) {
                destroy(node->left);
                destroy(node->right);
                delete node;
                count--;
            }
        }
    
        // 在以node为根的二叉搜索树中,返回最小键值的节点
        Node *minimum(Node *node) {
            if (node->left == nullptr)
                return node;
            return minimum(node->left);
        }
    
        // 在以node为根的二叉搜索树中,返回最大键值的节点
        Node *maximum(Node *node) {
            if (node->right == nullptr)
                return node;
            return maximum(node->right);
        }
    
        // 删除掉以node为根的二分搜索树中的最小节点
        // 返回删除节点后新的二分搜索树的根
        Node *removeMin(Node *node) {
    
            if (node->left == nullptr) {
                Node *rightNode = node->right;
                delete node;
                count--;
                return rightNode;
            }
            node->left->count--;
            node->left = removeMin(node->left);
            return node;
        }
    
        // 删除掉以node为根的二分搜索树中的最大节点
        // 返回删除节点后新的二分搜索树的根
        Node *removeMax(Node *node) {
    
            if (node->right == nullptr) {
                Node *leftNode = node->left;
                delete node;
                count--;
                return leftNode;
            }
            node->right->count--;
            node->right = removeMax(node->right);
            return node;
        }
    
        // 删除掉以node为根的二分搜索树中键值为key的节点
        // 返回删除节点后新的二分搜索树的根
        Node *remove(Node *node, Key key) {
    
            if (node == nullptr)
                return nullptr;
    
            if (key < node->key) {
                node->left->count--;
                node->left = remove(node->left, key);
                return node;
            } else if (key > node->key) {
                node->right->count--;
                node->right = remove(node->right, key);
                return node;
            } else { // key == node->key
    
                if (node->left == nullptr) {
                    Node *rightNode = node->right;
                    delete node;
                    count--;
                    return rightNode;
                }
    
                if (node->right == nullptr) {
                    Node *leftNode = node->left;
                    delete node;
                    count--;
                    return leftNode;
                }
    
                assert(node->left != nullptr && node->right != nullptr);
    
                Node *successor = new Node(minimum(node->right));
                count++;
    
                successor->count = node->count--;
    
                successor->right = removeMin(node->right);
                successor->left = node->left;
    
                delete node;
                count--;
    
                return successor;
            }
        }
    
    };
    
    展开全文
  • bool isBST(TreeNode *root) { //静态结点仅在第一次调用时创建 static TreeNode *prev; if(root != NULL) { if(!isBST(root->left)) return false; if(prev != NULL && ...
    bool isBST(TreeNode *root)
    {
        //静态结点仅在第一次调用时创建
        static TreeNode *prev;
        if(root != NULL)
        {
            if(!isBST(root->left))
                return false;
            if(prev != NULL && root->data < prev->data)
                return false;
            prev = root;
            if(!isBST(root->right))
                return false;
        }
        return true;
    }

     

    展开全文
  • 二叉搜索树c++实现

    2014-07-05 16:38:54
    使用二叉链表和c++来实现二叉搜索树,提供插入、删除、遍历、求最小节点、最大最节点等操作。
  • Leetcode96 不同的二叉搜索树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/unique-binary-search-trees/ 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给定一个整数 n,求以 1 … ...

    Leetcode96 不同的二叉搜索树

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/unique-binary-search-trees/

    博主Githubhttps://github.com/GDUT-Rp/LeetCode

    题目:

    给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

    示例 1:

    输入: 3
    输出: 5
    解释:
    给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
    
       1         3     3      2      1
        \       /     /      / \      \
         3     2     1      1   3      2
        /     /       \                 \
       2     1         2                 3
    

    解题思路:

    方法一:递归

    直观想法

    本问题可以用动态规划求解。

    给定一个有序序列 1 … n,为了根据序列构建一棵二叉搜索树。我们可以遍历每个数字 i,将该数字作为树根,1 … (i-1) 序列将成为左子树,(i+1) … n 序列将成为右子树。于是,我们可以递归地从子序列构建子树。 在上述方法中,由于根各自不同,每棵二叉树都保证是独特的。

    可见,问题可以分解成规模较小的子问题。因此,我们可以存储并复用子问题的解,而不是递归的(也重复的)解决这些子问题,这就是动态规划法。

    算法

    问题是计算不同二叉搜索树的个数。为此,我们可以定义两个函数:

    1. G ( n ) G(n) G(n): 长度为n的序列的不同二叉搜索树个数。

    2. F ( i , n ) F(i, n) F(i,n): 以i为根的不同二叉搜索树个数(1 \leq i \leq n1≤i≤n)。

    可见,

    G ( n ) G(n) G(n) 是我们解决问题需要的函数。

    稍后我们将看到, G ( n ) G(n) G(n) 可以从 F ( i , n ) F(i, n) F(i,n) 得到,而 F ( i , n ) F(i, n) F(i,n) 又会递归的依赖于 G ( n ) G(n) G(n)

    首先,根据上一节中的思路,不同的二叉搜索树的总数 G(n)G(n),是对遍历所有 i (1 <= i <= n) 的 F(i, n)F(i,n) 之和。换而言之:

    G ( n ) = ∑ i = 1 n F ( i , n ) ( 1 ) G(n) = \sum_{i=1}^{n} F(i, n) \qquad \qquad (1) G(n)=i=1nF(i,n)(1)
    特别的,对于边界情况,当序列长度为 1 (只有根)或为 0 (空树)时,只有一种情况。亦即:

    G ( 0 ) = 1 , G ( 1 ) = 1 G(0) = 1, \qquad G(1) = 1 G(0)=1,G(1)=1
    给定序列 1 ... n,我们选出数字 i 作为根,则对于根 i 的不同二叉搜索树数量 F ( i , n ) F(i, n) F(i,n),是左右子树个数的笛卡尔积,如下图所示:

    举例而言, F ( 3 , 7 ) F(3, 7) F(3,7),以 3 为根的不同二叉搜索树个数。为了以 3 为根从序列 [1, 2, 3, 4, 5, 6, 7] 构建二叉搜索树,我们需要从左子序列 [1, 2] 构建左子树,从右子序列 [4, 5, 6, 7] 构建右子树,然后将它们组合(即笛卡尔积)。 巧妙之处在于,我们可以将 [1,2] 构建不同左子树的数量表示为 G ( 2 ) G(2) G(2), 从 [4, 5, 6, 7] 构建不同右子树的数量表示为 G ( 4 ) G(4) G(4)。这是由于 G ( n ) G(n) G(n) 和序列的内容无关,只和序列的长度有关。于是, F ( 3 , 7 ) = G ( 2 ) ⋅ G ( 4 ) F(3,7) = G(2) \cdot G(4) F(3,7)=G(2)G(4)。 概括而言,我们可以得到以下公式:
    F ( i , n ) = G ( i − 1 ) ⋅ G ( n − i ) ( 2 ) F(i,n)=G(i−1)⋅G(n−i) \quad \quad(2) F(i,n)=G(i1)G(ni)(2)
    将公式 (1),(2) 结合,可以得到 G ( n ) G(n) G(n) 的递归表达公式:
    G ( n ) = ∑ i = 1 n G ( i − 1 ) ⋅ G ( n − i ) ( 3 ) G(n)= \sum_{i=1}^nG(i−1)⋅G(n−i)\quad \quad(3) G(n)=i=1nG(i1)G(ni)(3)
    为了计算函数结果,我们从小到大计算,因为 G ( n ) G(n) G(n) 的值依赖于 G ( 0 ) … G ( n − 1 ) G(0) … G(n-1) G(0)G(n1)

    根据以上的分析和公式,很容易实现计算 G ( n ) G(n) G(n) 的算法。 下面是示例:

    C++

    class Solution_LeetCode96 {
    public:
        int numTrees(int n) {
            int dp[n + 1];
            memset(dp, 0, sizeof(dp));
            dp[0] = dp[1] = 1;
            //  当n=1时,以1为根节点,左分支右分支个数均无,即G(1)=0
            //  当n=2时,以1为根节点,右分支个数为1,以2为根节点,左分支个数为1,G(2)=G(0)*G(1)+G(1)*G(0)
            //  假设n个结点,1为根节点,2为根节点,... n为根节点,
            //  G(n) = G(0)*G(n-1) + G(1)*G(n-2) + ... + G(n-2)*G(1) + G(n-1)*G(0)
            for (int i = 2; i <= n; ++i) {
                for (int j = 0; j < i; ++j) {
                    dp[i] += dp[j] * dp[i - j - 1];
                }
            }
            return dp[n];
        }
    };
    

    Java

    public class Solution {
      public int numTrees(int n) {
        int[] G = new int[n + 1];
        G[0] = 1;
        G[1] = 1;
    
        for (int i = 2; i <= n; ++i) {
          for (int j = 1; j <= i; ++j) {
            G[i] += G[j - 1] * G[i - j];
          }
        }
        return G[n];
      }
    }
    

    Python

    class Solution:
        def numTrees(self, n):
            """
            :type n: int
            :rtype: int
            """
            G = [0]*(n+1)
            G[0], G[1] = 1, 1
    
            for i in range(2, n+1):
                for j in range(1, i+1):
                    G[i] += G[j-1] * G[i-j]
    
            return G[n]
    
    
    复杂度分析
    • 时间复杂度 : 上述算法的主要计算开销在于包含 G[i] 的语句。因此,时间复杂度为这些语句的执行次数,也就是 ∑ i = 2 n i = ( 2 + n ) ( n − 1 ) 2 \sum_{i=2}^{n} i = \frac{(2+n)(n-1)}{2} i=2ni=2(2+n)(n1)。因此,时间复杂度为 O ( N 2 ) O(N^2) O(N2)

    • 空间复杂度 : 上述算法的空间复杂度主要是存储所有的中间结果,因此为​ O ( N ) O(N) O(N)

    展开全文
  • 二叉搜索树C++(VS2017)

    千次阅读 2018-12-22 09:41:04
    这篇博客会介绍二叉搜索树的插入和删除,还有为了方便演示,会介绍到中序递归遍历。  给定数组8,5,20,3,6,15,7,得到的二叉搜索树为: 中序遍历的结果:3,5,6,7,8,15,20,刚好是从小到大排序的。 ...

    一、二叉查找树:

           将小的数放到左儿子上,将大的数放到右儿子上,于是建树成功后,最左边的是最小的,最右边的是最大。中序遍历将会得到从小到大的排序顺序。这篇博客会介绍二叉搜索树的插入和删除,还有为了方便演示,会介绍到中序递归遍历。

          给定数组8,5,20,3,6,15,7,得到的二叉搜索树为:

    中序遍历的结果:3,5,6,7,8,15,20,刚好是从小到大排序的。

    二、叉搜索树的类:

    class BSTNode
    {
    public:
        int val;
        BSTNode *left, *right;
        BSTNode(int key):
            val(key){}
    };

    class BSTree
    {
    public:
        BSTNode *root;
        BSTree();
        void insert(int key);
        void InOrder(BSTNode *t);
        void BSTdelete(int key);
    private:
        void insert(BSTNode * &t,int key);
        BSTNode *&find_equal(BSTNode *&t, int key);

    };

    BSTNode类保存BSTree类的一个节点,BSTNode对象包含一个根节点。根节点不存储数据,根节点的*left开始储存数据,这和头结点不存储数据的链表很想,这样可以简化代码量。

    1、为了根节点不存储数据,构造函数为:

    BSTree::BSTree()
    {
        root = new BSTNode(-100000);
    }

     

    2、插入函数insert:将小的数值插入到左儿子上,大的数值插入到右儿子上,于是采取递归操作。

    void BSTree::insert(BSTNode * &t, int key)
    {
        if (!t)
            t = new BSTNode(key);
        else if (key < t->val)
            insert(t->left, key);
        else if (key > t->val)
            insert(t->right, key);
        else
            cout << "不要插入相同的键值" << endl;
    }

    为了在实际中(我为了中序遍历书写简单些,将*root设为了共有变量)不访问根节点*root,所以需要再加入一个函数:

    /*插入算法*/
    void BSTree::insert(int key)
    {
        insert(root->left, key);
    }

    3、删除函数delete:删除分为三种情况

       第一种:没有儿子:比如删除7所在节点的时候,直接找到这个节点删除

    第二种:只有一个儿子:比如删除20的时候,直接将它的不为空的儿子取代当前结点:

    新的搜索树:

    第三种:左右儿子都不为空:比如删除数值为5的节点,此时找到以该节点为树根的树的最右边的节点,可以发现是7。将找到的节点和原节点替换(就是将5和7替换),删掉原来的节点。

    删除5后的图:

    代码如下:


    /*找到需要删除数值所在的节点*/
    BSTNode *&BSTree::find_equal(BSTNode *&t, int key)
    {
        if (!t)
        {
            cout << "二叉树中不存在改数值!" << endl;
            return t;
        }
        if (key < t->val)
            find_equal(t->left, key);
        else if (key > t->val)
            find_equal(t->right, key);
        else
            return t;

    }

    void BSTree::BSTdelete(int key)
    {
        BSTNode *&p = find_equal(root->left, key);
        if (p)
        {
            BSTNode *t = p;
            if (t->left&&t->right)
            {
                //左右子树都不为空
                BSTNode *y = t;
                BSTNode *x = t->right;
                while (x->left)
                {
                    y = x;
                    x = x->left;
                }
                if (y == t)  //y与t重合的情况
                    y->right = x->right;
                else
                    y->left = x->left;
                p = x;
                x->left = t->left;
                x->right = t->right;
            }
            else
            {
                //只有一个儿子
                p = t->left ? t->left : t->right;
            }
            delete t;
        }
    }

    三、总的代码如下:需要vs2017才能运行,因为之前的版本指针的判断不同,我没有对指针进行初始化。

    // BSTree.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    
    #include <iostream>
    #include<queue>
    using namespace std;
    class BSTNode
    {
    public:
    	int val;
    	BSTNode *left, *right;
    	BSTNode(int key):
    		val(key){}
    };
    
    class BSTree
    {
    public:
    	BSTNode *root;
    	BSTree();
    	void insert(int key);
    	void InOrder(BSTNode *t);
    	void BSTdelete(int key);
    private:
    	void insert(BSTNode * &t,int key);
    	BSTNode *&find_equal(BSTNode *&t, int key);
    
    };
    
    BSTree::BSTree()
    {
    	root = new BSTNode(-100000);
    }
    void BSTree::insert(BSTNode * &t, int key)
    {
    	if (!t)
    		t = new BSTNode(key);
    	else if (key < t->val)
    		insert(t->left, key);
    	else if (key > t->val)
    		insert(t->right, key);
    	else
    		cout << "不要插入相同的键值" << endl;
    }
    
    /*插入算法*/
    void BSTree::insert(int key)
    {
    	insert(root->left, key);
    }
    
    void BSTree::InOrder(BSTNode *t)
    {
    	if (t)
    	{
    		InOrder(t->left);
    		cout << "<"<<t->val << ">";
    		InOrder(t->right);
    	}
    }
    
    /*找到需要删除数值所在的节点*/
    BSTNode *&BSTree::find_equal(BSTNode *&t, int key)
    {
    	if (!t)
    	{
    		cout << "二叉树中不存在改数值!" << endl;
    		return t;
    	}
    	if (key < t->val)
    		find_equal(t->left, key);
    	else if (key > t->val)
    		find_equal(t->right, key);
    	else
    		return t;
    
    }
    
    void BSTree::BSTdelete(int key)
    {
    	BSTNode *&p = find_equal(root->left, key);
    	if (p)
    	{
    		BSTNode *t = p;
    		if (t->left&&t->right)
    		{
    			//左右子树都不为空
    			BSTNode *y = t;
    			BSTNode *x = t->right;
    			while (x->left)
    			{
    				y = x;
    				x = x->left;
    			}
    			if (y == t)  //y与t重合的情况
    				y->right = x->right;
    			else
    				y->left = x->left;
    			p = x;
    			x->left = t->left;
    			x->right = t->right;
    		}
    		else
    		{
    			//只有一个儿子
    			p = t->left ? t->left : t->right;
    		}
    		delete t;
    	}
    }
    int main()
    {
    	BSTree tree;
    	int key,count ;
    	cout << "1、添加树     2、输入要删除的数字    3、退出" << endl;
    	cin >> count;
    	while (count != 3)
    	{
    		if (count == 1)
    		{
    			cout << "请输入要添加的数据:" << endl;
    			cin >> key;
    			tree.insert(key);
    		}
    		if (count == 2)
    		{
    			cout << "请输入要删除的数据:" << endl;
    			cin >> key;
    			tree.BSTdelete(key);
    		}
    		cout << "\n搜索树中序遍历结果:" << endl;
    		cout << "{";
    		tree.InOrder(tree.root->left);
    		cout << "}" << endl;
    
    		cout << "1、添加树     2、输入要删除的数字    3、退出" << endl;
    		cin >> count;
    	}
    	cout << "退出!" << endl;
    	return 0;
    }
    
    

     

     

     

     

     

     

     

    标题

     

    展开全文
  • 有序链表转换二叉搜索树 题目 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 测试样例 ...
  • 109 有序链表转换二叉搜索树 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 示例: 给定的...
  • C++实现二叉搜索树

    2020-07-14 15:16:06
    二叉搜索树是数据结构中树形结构一种。它或者是一棵空树,或者具有以下特性: a.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 b.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 ...
  • 给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的...
  • 修剪二叉搜索树 题目 给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根...
  • 不同的二叉搜索树 题目 给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种? 测试样例 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 /...
  • C++ 实现 二叉搜索树

    2020-01-06 16:01:52
    1.二叉搜索树的特性 1.对于任意节点,比其左子树中任意节点都大,比其右子树中任意节点都小。 2.最左侧的节点一定是最小的,最右侧的节点一定是最大的。 3.中序遍历:是一个有序序列。 2.二叉搜索树的模拟实现 ...
  • 验证二叉搜索树 C++ 思路: 自顶向下遍历:每一个节点有一个对应的区间 class Solution { public: bool isValidBST(TreeNode* root) { return dfs(root, INT_MIN, INT_MAX); } bool dfs(TreeNode* root, long ...
  • 今天我们的主题是二叉搜索树也有叫二叉排序树还是和以前一样,我们谈某个技术之前先谈谈出现的理由:二叉搜索树那么到底是什么,做什么的,根据字面意思其实就是使用特定二叉树的特性去查找树里的某个元素。...
  • 思路:动态规划。参考http://www.cnblogs.com/grandyang/p/4299608.html class Solution { public: int numTrees(int n) { vector&lt;int&gt; dp(n+1,0); dp[0]=1; dp[1]=1; for(int i=2;...
  • 二叉搜索树详解(C++实现)

    千次阅读 多人点赞 2018-03-05 16:35:10
    二叉搜索树的定义 二叉搜索树,也称有序二叉树,排序二叉树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若任意节点的右子树不空,则右子树...
  • LeetCode第 108 题:将有序数组转化为二叉搜索树(C++)_zj-CSDN博客的进阶。 一个高度平衡二叉树是指一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1。 108题的时候,我们可以很轻松地通过下标计算出中间...
  • 判断是否为二叉搜索树C++实现)

    千次阅读 2019-08-09 11:56:28
    给定一个根结点如何判断一棵树是否为二叉搜索树呢?下面我们用三种方式来处理这个问题 方法一: 根据二叉搜索树的特征,二叉搜索树的中序遍历应该为一个有序集合 对树进行中序遍历,将结果保存在temp数组中 ...
  • 使用C++实现常见的关于二叉查找的操作接口
  • Leetcode98 验证二叉搜索树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/validate-binary-search-tree/ 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给定一个二叉树,判断其是否...
  • c++ 二叉搜索树的创建 代码解释

    千次阅读 2020-05-20 16:57:04
    二叉搜索树的定义: 二叉树中每一个节点: 若其左子树存在,则其左子树中每个节点的值都不大于该节点值, 若其右子树存在,则其右子树中每个节点的值都不小于该节点值。 如果想了解更多二叉搜索树的定义:数据结构...
  • 二叉搜索树的实现(C++

    千次阅读 2019-04-19 21:41:46
    二叉搜索树又称为二叉排序树,它可能是一棵空树,亦或是一棵具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有结点的值都小于根结点的值。 若它的右子树不为空,则右子树上所有结点的值都大于根结点的值...
  • 1、二叉搜索树(二叉排序树)的性质: 1、任意一个节点的值都大于左子树中所有节点的值。 2、任意一个节点的值都小于右子树中所有节点的值。 3、中序遍历按从小到大排列。 4、可以是一颗空树 5、不能有重复的...
  • 最优二叉搜索树C++实现

    千次阅读 2018-06-05 12:08:37
    当s[1][n]=k 时,Xk 为最优搜索树的根节点。T(1,n)的子问题为T(1,k-1)和T(k+1,n),同理可知T(1,k-1)的根节点下标为s[1][k-1]。以此类推可得此问题最优搜索树如图: 算法设计课作业,参考《算法设计与分析》,王晓东著...
  • 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数。 节点的右子树只包含大于当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。...
  • leetcode 99. 恢复二叉搜索树C++):在不改变二叉搜索树结构的情况下,恢复这棵树错误地交换的两个节点。
  • 牛客题霸 [将升序数组转化为平衡二叉搜索树]C++题解/答案 题目描述 给出一个升序排序的数组,将其转化为平衡二叉搜索树(BST). 题解: 二叉搜索树的定义: 二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:...
  • 文章目录一、关于最优二叉搜索树1. 问题描述:2. 问题分析:二、算法实现1. 自底向上 非递归 的动态规划2. 运行结果展示 一、关于最优二叉搜索树 1. 问题描述: 给定一个由n个互异的关键字组成的有序序列K={k1<...
  • 99. 恢复二叉搜索树 题目链接 由于二叉搜索树中序遍历是一个递增且有序,因此可以根据这个特性确定两个错误节点。 C++: /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,929
精华内容 6,771
关键字:

二叉搜索树c++

c++ 订阅