算法铺子之二分搜索树

0.二分搜索树

二分搜索树(Binary Search Tree,BST)是一颗典型的二叉树,任何节点的键值大于等于该节点左子树中的所有键值,小于等于该节点右子树中的所有键值。 二叉搜索树可以看作是有序集合的树形存储,是一种用途非常广泛的基础数据结构。

1.二分搜索树的优势

二分搜索树不仅能够高效的查找数据,还可以高效的插入和删除数据。时间复杂度都为O(logn)。

这里写图片描述

2.二分搜索树的操作

2.1 插入

插入操作是一个不断递归的过程,假设现在有一棵二分搜索树如下图所示:
这里写图片描述
现在,想要插入一个新的元素,这个新的元素的key为60
这里写图片描述
这时候,新元素的key和树的根节点的key作比较,60>41,所以新节点要插入到根结点的右子树。
这里写图片描述
同样,60>58,需要插入到58这个节点的右子树中,所以最后结果如下:
这里写图片描述

2.2 查找

查找操作和插入操作类似,假设现在要查找key为42的节点
这里写图片描述
因为42比41到,所以要到41的右子树中查找。
这里写图片描述
现在42比58小,所以要打58的左子树种查找。
这里写图片描述
然后42比50小,就到50的左子树种查找,欸,发现找到了42,查找操作结束。
这里写图片描述

2.3 广度优先遍历

广度优先遍历也就是层次优先遍历,遍历顺序是一层一层地从左到右的遍历方式。假设有如下图所示的二分搜索树,那么遍历结果应该为:28,16,30,13,22,29,42。
这里写图片描述
为了实现这种遍历,需要借助一个辅助的数据结构—-队列。如果现在要做广度优先遍历,那么先把根结点入队。
这里写图片描述
然后把28出队,并把28的左右孩子节点入队。
这里写图片描述
然后把16和30出队,并把16和30的孩子节点入队。
这里写图片描述
然后把13,22,29,42出队,由于他们都没有孩子节点了,所以遍历也就结束了。
这里写图片描述

2.4 删除最小值和最大值节点

由于二分搜索树的性质,很容易能想到最小值的节点,就是树的最左边的叶子节点,而最大值的节点是最右边的叶子节点。在删除最大值或最小值节点时,当然不能直接把最小值或最大值节点删掉就好了,因为如果此时最小值节点有右孩子或最大值节点有左孩子,那么这样删除会有问题。如下图中13是最小值节点,他没有右孩子,所以直接删除这个节点就行了,但是最大值节点58有左孩子,直接删除58这个节点是不行的。
这里写图片描述
像这种情况,就需要将58的左子树作为41的右子树进行连接。
这里写图片描述

2.5 删除任意节点

如果需要删除的节点没有孩子或者只有孩子,那么思路和2.4中删除最小值和最大值节点的思路是一样的,但是如果待删除节点的左右孩子节点都存在的话应该怎么办呢?

假设现在要删除这棵树的58节点叫d。
这里写图片描述
那么我们同样需要找一个节点来代替58,但这个节点不应该是50或者60,而应该是右孩子的左孩子(59)。因为58会大于它的左孩子,小于它的右孩子。也就是说58的右子树的所有节点也同样都大于58的左子树的所有节点。所以找替换节点在58的右子树中找没毛病,但也不能瞎找。应该找58的右子树种的最小值节点。也就是59。
这里写图片描述
我们也可以比较59为s,其实s是d的后继节点。
这里写图片描述
现在找到了待删除节点d的后继节点s,接下来只需把s删掉,替换到d的位置,然后把d删除即可。
这里写图片描述

3 代码实现

template <typename Key, typename Value>
class BST{

private:
    struct Node{
        Key key;
        Value value;
        Node *left;
        Node *right;

        Node(Key key, Value value){
            this->key = key;
            this->value = value;
            this->left = this->right = NULL;
        }

        Node(Node* node)
        {
            this->key = node->key;
            this->value = node->value;
            this->left = node->left;
            this->right = node->right;
        }
    };

    Node *root;
    int count;

public:
    BST(){
        root = NULL;
        count = 0;
    }
    ~BST(){
        destory(root);
    }

    int size(){
        return count;
    }

    bool isEmpty(){
        return count == 0;
    }

    void insert(Key key, Value value){
        root = insert(root, key, value);
    }

    bool contain(Key key){
        return contain(root, key);
    }

    Value* search(Key key){
        return search(root, key);
    }

    void remove(Key key)
    {
        root = remove(root, key);
    }

    void level_order()
    {
        queue<Node*> queue;
        queue.push(root);
        while (!queue.empty())
        {
            Node* node = queue.front();
            queue.pop();
            cout << node->key << endl;
            if (node->left)
                queue.push(node->left);
            if (node->right)
                queue.push(node->right);
        }
    }

    Key minmum()
    {
        Node* node = root;
        while (node->left)
        {
            node = node->left;
        }
        return node->key;
    }

    Key maxmum()
    {
        Node* node = root;
        while (node->right)
        {
            node = node->right;
        }
        return node->key;
    }

    void remove_min()
    {
        if (!root)
            return;
        root = remove_min(root);
    }

    void remove_max()
    {
        if (!root)
            return;
        root = remove_max(root);
    }

private:
    Node* minmum(Node* node)
    {
        if (!node)
            return nullptr;
        while (node->left)
        {
            node = node->left;
        }
        return node;
    }

    Node* maxmum(Node* node)
    {
        if (!node)
            return nullptr;
        while (node->right)
        {
            node = node->right;
        }
        return node;
    }

    Node* remove(Node* node,Key key)
    {
        if (node == nullptr)
        {
            return nullptr;
        }
        if (key < node->key)
        {
            node->left = remove(node->left, key);
            return node;
        }
        else if (key > node->key)
        {
            node->right = remove(node->right, key);
            return node;
        }
        else
        {
            if (node->left == nullptr)
            {
                Node* right = node->right;
                delete node;
                count--;
                return right;
            }
            if (node->right == nullptr)
            {
                Node* left = node->left;
                delete node;
                count--;
                return left;
            }

            Node* d = node;
            Node* s = new Node(minmum(d->right));
            ++count;
            s->right = remove_min(node->right);
            s->left = node->left;
            delete d;
            --count;
            return s;

        }
    }

    Node* remove_min(Node* node)
    {
        if (node->left == nullptr)
        {
            Node* right_node = node->right;
            delete node;
            count--;
            return right_node;
        }
        node->left = remove_min(node->left);
        return node;
    }

    Node* remove_max(Node* node)
    {
        if (node->right == nullptr)
        {
            Node* left_node = node->left;
            delete node;
            count--;
            return left_node;
        }
        node->right = remove_max(node->right);
        return node;
    }

    void destory(Node* node)
    {
        if (node)
        {
            destory(node->left);
            destory(node->right);
            delete node;
            --count;
        }
    }
    // 向以node为根的二叉搜索树中,插入节点(key, value)
    // 返回插入新节点后的二叉搜索树的根
    Node* insert(Node *node, Key key, Value value){

        if (node == NULL){
            count++;
            return new Node(key, value);
        }

        if (key == node->key)
            node->value = value;
        else if (key < node->key)
            node->left = insert(node->left, key, value);
        else    // key > node->key
            node->right = insert(node->right, key, value);

        return node;
    }

    // 查看以node为根的二叉搜索树中是否包含键值为key的节点
    bool contain(Node* node, Key key){

        if (node == NULL)
            return false;

        if (key == node->key)
            return true;
        else if (key < node->key)
            return contain(node->left, key);
        else // key > node->key
            return contain(node->right, key);
    }

    // 在以node为根的二叉搜索树中查找key所对应的value
    Value* search(Node* node, Key key){

        if (node == NULL)
            return NULL;

        if (key == node->key)
            return &(node->value);
        else if (key < node->key)
            return search(node->left, key);
        else // key > node->key
            return search(node->right, key);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

alw_123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值