C++【二叉搜索树的总结与模拟实现】

前言介绍

        二叉搜索树(Binary Search Tree)顾名思义,是一个为搜索效率而生的数据结构,那接下来我们就先了解二叉搜索树的概念及如何实现。

一、概念

二叉搜索树别名:二叉排序树 / 二叉查找树,它可以是一棵空树,或者是具备以下性质的树:

【非空二叉搜索树必须具备以下性质】

        1. 左子树不为空,左子树的所有节点值 < 根结点值

        2. 右子树不为空,右子树的所有节点值 > 根结点值

图形实例:(必须严格满足性质)

二、模拟实现

2.1 创造树的节点及树的结构

//思考:创建一个二叉搜索树,首先要构造树的节点,其次再实现树的结构
//创建树的节点时,必须思考节点内部应该包含哪些变量?
// 1. 节点代表的值,2. 节点指向左右子树的指针,3. 指向父亲节点的指针
//开始构建树的节点,我们希望节点内部的成员可以被外界使用,所以使用struct类
template <class V>
struct BSTreeNode
{
    BSTreeNode(const V& val)
        : _val(val)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
    {}
    V _val;
    BSTreeNode<V>* _left;
    BSTreeNode<V>* _right;
    BSTreeNode<V>* _parent;
};
//构造完节点,下一步去设计树的结构,我们希望二叉搜索树只对外界展现成员函数,所以使用class类
template <class V>
class BSTree
{
public:
    typedef BSTreeNode<V> Node;

    //插入
    bool insert(const V& val);
    //删除
    bool erase();
    //查找
    Node* find(const V& val);
    //中序遍历 -> 有序
    void inorder();
    
private:
    Node* _root = nullptr; //这里使用指针的原因是动态的增删查改
};

2.2 编写成员函数

(1)插入insert

        按照二叉搜索树的性质来插入即可,需要注意的是下面代码不允许插入相同值

 bool insert(const V& val)
    {
        //空树
        if(_root == nullptr)
        {
            _root = new Node(val);
            return true;
        }
        //非空树
        else
        {
            Node* cur = _root;
            Node* parent = nullptr;
            while(cur)
            {
                if(cur->_val > val)
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else if(cur->_val < val)
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else
                {
                    cout << "不允许插入已有的数据" << endl;
                    return false;
                }
            }

            //已经找到插入节点的父亲节点,开始判断插入左边还是右边
            Node* newnode = new Node(val);

            // 比根小,去左边插入
            if(parent->_val > val)
            {
                parent->_left = newnode;
            }
            // 比根大,去右边插入
            else
            {
                parent->_right = newnode;
            }
            newnode->_parent = parent;
            return true;
        }
    }

(2)查找find

        按照二叉搜索树的规则来查找,会发现最坏情况下只需要查找高度次,后面有测效率的代码

Node* find(const V& val)
{
    Node* cur = _root;
    while(cur)
    {
        if(cur->_val > val)
        {
            cur = cur->_left;
        }
        else if(cur->_val < val)
        {
            cur = cur->_right;
        }
        else
        {
            return cur;
        }
    }
    return nullptr;
}

(3)中序遍历 inorder

        只有中序遍历二叉搜索树才是有序,所以这里只使用中序遍历

void inorder()
{
    _inorder(_root);
    cout << endl;
}

void _inorder(Node* root) //像这种被封装一层的函数,我们一般不会对外开放,所以要放到private里
{
    if(root == nullptr)
        return;
    _inorder(root->_left);
    cout << root->_val << " ";
    _inorder(root->_right);
}

(4)删除erase【重点】

        在删除节点这里,是会影响二叉搜索树的性质的,所以我们要分下面4种情况来讨论:

情况1:被删除的节点不存在,直接返回false
情况2:被删除的节点存在,但为叶节点,则直接删除,不会影响二叉搜索树

情况3:被删除的节点的只有左孩子

情况4:被删除的节点的只有右孩子

情况2、3、4可以合并解决:

        因为我们会发现,情况3、4只是将节点删除,再连接父节点和孩子节点即可,基本对树的结构也无影响,所以情况2、3、4可以合并解决

情况5:被删除的节点有左右孩子

当被删除节点有左右孩子节点的时候,如下图:

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

终将向阳而生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值