【C++进阶】二叉搜索树

【C++进阶】二叉搜索树

🥕个人主页:开敲🍉

🔥所属专栏:C++🥭

🌼文章目录🌼

1. 二叉搜索树的概念

2. 二叉搜索树的性能分析

3. 二叉搜索树的插入

4. 二叉搜索树的查找

5. 二叉搜索树的删除

6. 二叉搜索树的实现代码

1. 二叉搜索树的概念

  二叉搜索树又称二叉排序树,它或者是一颗空树,或者是具有以下性质的二叉树:

① 若它的左子树不为空,则左子树上节点的值都小于等于根节点的值。

② 若它的右子树不为空,则右子树上节点的值都大于等于根节点的值。

③ 它的左右子树也要满足 二叉搜索树 的性质。

④ 二叉搜索树中可以支持插入相等的值,也可以不支持插入相等的值,具体看使用的场景。

2. 二叉搜索树的性能分析

  最优情况下,二叉搜索树为完全二叉树,其高度为:log(N),时间复杂度为:O(log(N))。

  最坏情况下,二叉搜索树为单链表形态,其高度为:(N/2),时间复杂度为:O(N)。

  所以综合而言,二叉搜索树的时间复杂度为:O(N)。

3. 二叉搜索树的插入

  插入的具体过程如下:

① 树为空,则直接插入节点,并且使其作为根节点。

② 树不为空,根据二叉搜索树的性质:插入值比当前节点大往右走;插入值比当前节点小往左走;如果我们实现的是允许插入相同值的二叉搜索树,则插入值与当前节点值相同时,往左往右都可以。找到空位置后插入新节点。

  不支持插入相同值的二叉搜索树的插入参考代码:

    void Insert(const K& key)
    {
        if (!_root) _root = new Node(key);
        else
        {
            Node* parent = nullptr;
            Node* cur = _root;
            while (cur)
            {
                parent = cur;
                if (cur->_key > key) cur = cur->left;
                else if (cur->_key < key) cur = cur->right;
                else return;
            }
            if (parent->_key > key) parent->left = new Node(key);
            else if (parent->_key < key) parent->right = new Node(key);
        }
    }

  支持插入相同值的二叉搜索树的插入参考代码:

    void Insert(const K& key)
    {
        if (!_root) _root = new Node(key);
        else
        {
            Node* parent = nullptr;
            Node* cur = _root;
            while (cur)
            {
                parent = cur;
                if (cur->_key >= key) cur = cur->left;
                else if (cur->_key < key) cur = cur->right;
                else return;
            }
            if (parent->_key >= key) parent->left = new Node(key);
            else if (parent->_key < key) parent->right = new Node(key);
        }
    }

4. 二叉搜索树的查找

  ① 从根开始比较,查找x。x比当前节点的值大就往右查找;x比当前节点的值小就往左查找。

  ② 查找高度次,如果走到空了则说明这个值不存在。

  ③ 如果不支持插入相同的值,查找到x就可以返回;如果支持,则需要查找到中序遍历的第一个x。

  不支持插入相同值的二叉搜索树的查找参考代码:

    bool Find(const K& key)
    {
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key) cur = cur->left;
            else if (cur->_key < key) cur = cur->right;
            else return true;
        }
        return false;
    }

5. 二叉搜索树的删除

  从根开始查找元素。如果查找到空,则说明要删除的值不存在;否则,要删除的元素存在,分为以下四种情况处理:(假设要删除节点为 N)

① 要删除的节点为叶子节点:此时直接将 N 删除,使其父节点指向 N 的指针指向nullptr。

② 要删除的节点左孩子为空,而右孩子不为空:此时我们将其父节点指向 N 位置的指针指向 N->right。通俗一点的理解就是将我的孩子托付给父亲,随后删除我。

③ 要删除的节点左孩子不为空,右孩子为空:此时我们将其父节点指向 N 位置的指针指向 N->left。

④ 要删除的节点左右孩子均不为空:这种情况最为复杂。我们此时无法直接删除 N ,因为 N 左右均有孩子无处安放,此时有一个方法专门解决这个问题;我们去 N 节点的左子树寻找最大值(max) 或者 去 N 节点的右子树寻找最小值(min)。让这个值和 N 的值进行交换,随后删除 max 或 min 原本所在节点。

  二叉搜索树的删除参考代码:

    void Delete(const K& key)
    {
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key)
            {
                parent = cur;
                cur = cur->left;
            }
            else if (cur->_key < key)
            {
                parent = cur;
                cur = cur->right;
            }
            else
            {
                if (IsLeafNode(cur))//情况 ① 
                {
                    if (!parent) _root = nullptr;
                    else
                    {
                        if (parent->left == cur) parent->left = nullptr;
                        if (parent->right == cur) parent->right = nullptr;
                    }
                }
                else
                {
                    if (!cur->right)//情况 ③ 
                    {
                        if (cur == _root) _root = cur->left;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->left;
                            else parent->right = cur->left;
                        }
                    }
                    else if (!cur->left)//情况 ②
                    {
                        if (cur == _root) _root = cur->right;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->right;
                            else parent->right = cur->right;
                        }
                    }
                    else//情况 ④ 
                    {
                        parent = cur;
                        Node* tmp = cur->right;
                        while (tmp->left)
                        {
                            parent = tmp;
                            tmp = tmp->left;
                        }
                        swap(cur->_key, tmp->_key);
                        if (parent->left == tmp) parent->left = tmp->right;
                        else parent->right = tmp->right;
                    }
                }
                break;
            }
        }
    }

6. 二叉搜索树的实现代码

//不允许插入相同值

#pragma once


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


template <class K>
class BSTreeNodeK
{
public:
    K _key;
    BSTreeNodeK* left;
    BSTreeNodeK* right;
    BSTreeNodeK(const K& key)
        :_key(key),
        left(nullptr),
        right(nullptr)
    {}
};


template <class K>
class BSTreeK
{
    typedef BSTreeNodeK<K> Node;
public:
    void Insert(const K& key)
    {
        if (!_root) _root = new Node(key);
        else
        {
            Node* parent = nullptr;
            Node* cur = _root;
            while (cur)
            {
                parent = cur;
                if (cur->_key > key) cur = cur->left;
                else if (cur->_key < key) cur = cur->right;
                else return;
            }
            if (parent->_key > key) parent->left = new Node(key);
            else if (parent->_key < key) parent->right = new Node(key);
        }
    }

    bool IsLeafNode(Node* root) { return !root->left && !root->right; }

    void Delete(const K& key)
    {
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key)
            {
                parent = cur;
                cur = cur->left;
            }
            else if (cur->_key < key)
            {
                parent = cur;
                cur = cur->right;
            }
            else
            {
                if (IsLeafNode(cur))
                {
                    if (!parent) _root = nullptr;
                    else
                    {
                        if (parent->left == cur) parent->left = nullptr;
                        if (parent->right == cur) parent->right = nullptr;
                    }
                }
                else
                {
                    if (!cur->right)
                    {
                        if (cur == _root) _root = cur->left;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->left;
                            else parent->right = cur->left;
                        }
                    }
                    else if (!cur->left)
                    {
                        if (cur == _root) _root = cur->right;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->right;
                            else parent->right = cur->right;
                        }
                    }
                    else
                    {
                        parent = cur;
                        Node* tmp = cur->right;
                        while (tmp->left)
                        {
                            parent = tmp;
                            tmp = tmp->left;
                        }
                        swap(cur->_key, tmp->_key);
                        if (parent->left == tmp) parent->left = tmp->right;
                        else parent->right = tmp->right;
                    }
                }
                break;
            }
        }
    }

    bool Find(const K& key)
    {
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key) cur = cur->left;
            else if (cur->_key < key) cur = cur->right;
            else return true;
        }
        return false;
    }

    void Precedent()
    {
        Node* pmove = _root;
        _Precedent(pmove);
        cout << endl;
    }
private:

    void _Precedent(Node* root)
    {
        if (!root) return;
        _Precedent(root->left);
        cout << root->_key << ' ';
        _Precedent(root->right);
    }
    Node* _root = nullptr;
};

// key_value 二叉搜索树

//使用场景:停车场计费系统、中译英系统等

template <class K,class V>
class BSTreeNodeKV
{
public:
    K _key;
    V _value;
    BSTreeNodeKV* left;
    BSTreeNodeKV* right;
    BSTreeNodeKV(const K& key,const V& value)
        :_key(key),
        _value(value),
        left(nullptr),
        right(nullptr)
    {}
};


template <class K,class V>
class BSTreeKV
{
    typedef BSTreeNodeKV<K,V> Node;
public:
    void Insert(const K& key,const V& value)
    {
        if (!_root) _root = new Node(key,value);
        else
        {
            Node* parent = nullptr;
            Node* cur = _root;
            while (cur)
            {
                parent = cur;
                if (cur->_key > key) cur = cur->left;
                else if (cur->_key < key) cur = cur->right;
                else return;
            }
            if (parent->_key > key) parent->left = new Node(key,value);
            else if (parent->_key < key) parent->right = new Node(key,value);
        }
    }

    bool IsLeafNode(Node* root) { return !root->left && !root->right; }

    void Delete(const K& key)
    {
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key)
            {
                parent = cur;
                cur = cur->left;
            }
            else if (cur->_key < key)
            {
                parent = cur;
                cur = cur->right;
            }
            else
            {
                if (IsLeafNode(cur))
                {
                    if (!parent) _root = nullptr;
                    else
                    {
                        if (parent->left == cur) parent->left = nullptr;
                        if (parent->right == cur) parent->right = nullptr;
                    }
                }
                else
                {
                    if (!cur->right)
                    {
                        if (cur == _root) _root = cur->left;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->left;
                            else parent->right = cur->left;
                        }
                    }
                    else if (!cur->left)
                    {
                        if (cur == _root) _root = cur->right;
                        else
                        {
                            if (parent->left == cur) parent->left = cur->right;
                            else parent->right = cur->right;
                        }
                    }
                    else
                    {
                        parent = cur;
                        Node* tmp = cur->right;
                        while (tmp->left)
                        {
                            parent = tmp;
                            tmp = tmp->left;
                        }
                        swap(cur->_key, tmp->_key);
                        if (parent->left == tmp) parent->left = tmp->right;
                        else parent->right = tmp->right;
                    }
                }
                break;
            }
        }
    }

    string Find(const K& key)
    {
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key) cur = cur->left;
            else if (cur->_key < key) cur = cur->right;
            else return cur->_value;
        }
        return "false";
    }

    void Precedent()
    {
        Node* pmove = _root;
        _Precedent(pmove);
        cout << endl;
    }
private:

    void _Precedent(Node* root)
    {
        if (!root) return;
        _Precedent(root->left);
        cout << root->_key << ' ';
        _Precedent(root->right);
    }
    Node* _root = nullptr;
};

                                                  创作不易,点个赞呗,蟹蟹啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值