二叉搜索树

二叉搜索树:其又叫做二叉排序树,它或是一个空树,或是具有以下性质:
1、若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
2、若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
3、它的左右子树也分别为二叉搜索树。

如下图所示的二叉搜索树:
这里写图片描述
给出具体的树的节点的结构如下:(左子树,右子树,key值,value值)

template<class k,class v>
struct BSTreeNode
{
    BSTreeNode(const k&key, const v&value)
    :_pLeft(NULL)
    , _pRight(NULL)
    , _key(key)//要查找的值
    , _value(value)//数组的下标
    {}
    BSTreeNode<k, v>*_pLeft;
    BSTreeNode<k, v>*_pRight;
    k _key;
    v _value;
};

下面来看看二叉搜索树的具体操作:
先来看看查找操作:

这里写图片描述
具体的操作代码为:

    pNode Find(const k&key)//查找函数
    {
        pNode pcur = _pRoot;
        while (pcur)
        {
            if (key == pcur->_key)
            {
                return pcur;
            }
            else if (pcur->_key > key)
            {
                pcur = pcur->_pLeft;
            }
            else
            {
                pcur = pcur->_pRight;
            }
        }
        return NULL;
    }

插入操作:
1.在向二叉搜索树中插入新元素时,先要检测这个元素是否在树中已经存在。若已经存在,则不进行插入,返回false;
2.若需插入的元素小于根节点的key,则继续走到其左子树。
3.若需插入的元素大于根节点的key,则继续走到其右子树。

这里写图片描述
具体的操作代码如下:

bool insert(const k&key, const v&value)//插入
    {
        if (_pRoot == NULL)
        {
            _pRoot = new Node(key, value);
            return true;
        }
        pNode pcur = _pRoot;
        pNode parent = NULL;
        //1.找到待插入的位置
        while (pcur)
        {
            if (key < pcur->_key)
            {
                parent = pcur;
                pcur = pcur->_pLeft;
            }
            else if (key > pcur->_key)
            {
                parent = pcur;
                pcur = pcur->_pRight;
            }
            else
                return false;
        }
        //2.插入新节点
        pcur = new Node(key, value);
        if (key < parent->_key)
        {
            parent->_pLeft = pcur;
        }
        if (key > parent->_key)
        {
            parent->_pRight = pcur;
        }
    }

删除操作:
二叉搜索树的删除操作较为复杂,具体分为四种情况:
1.要删除的节点无左右孩子。
2.要删除的节点只有左孩子。
3.要删除的节点只有右孩子。
4.要删除的节点有左右孩子。

因为情况一可以归结到情况二、三中,所以我们先从情况二开始看。

这里写图片描述

情况三与情况二类似。不展开具体的讨论。

情况四:
这里写图片描述
删除的具体代码实现为:

bool remove(const k&key)//删除
    {
            pNode parent = NULL;
            pNode pcur = _pRoot;
            //1.找到待删除的节点
            while (pcur)
            {
                if (pcur->_key > key)
                {
                    parent = pcur;
                    pcur = pcur->_pLeft;
                }
                else if (pcur->_key < key)
                {
                    parent = pcur;
                    pcur = pcur->_pRight;
                }
                else
                {
                    break;
                }
            }
            if (pcur)
            {
                if (pcur->_pLeft == NULL)//只有右子树
                {
                    if (pcur != _pRoot)
                    {
                        if (parent->_pLeft == pcur)
                            parent->_pLeft = pcur->_pRight;
                        else
                            parent->_pRight = pcur->_pRight;
                    }
                    else
                        _pRoot = pcur->_pRight;
                    delete pcur;
                    pcur = NULL;
                }
                else if (pcur->_pRight == NULL)//只有左子树
                {
                    if (pcur != _pRoot)
                    {
                        if (parent->_pLeft == pcur)
                            parent->_pLeft = pcur->_pLeft;
                        else
                            parent->_pRight = pcur->_pRight;
                    }
                    else
                        _pRoot = pcur->_pLeft;
                    delete pcur;
                    pcur = NULL;
                }
                else      //左右子树存在
                {
                    pNode parent = pcur;
                    pNode pDel = pcur->_pRight;//找到其右子树中序下的第一个节点
                    while (pDel->_pLeft)//找到其左子树
                    {
                        parent = pDel;
                        pDel = pDel->_pLeft;
                    }
                    pcur->_key = pDel->_key;
                    pcur->_value = pDel->_value;
                    if (parent->_pLeft == pDel)
                        parent->_pLeft = pDel->_pLeft;
                    else
                        parent->_pRight = pDel->_pRight;
                    delete pDel;
                    pDel = NULL;
                }
                return true;
            }
            return false;
        }
    //注:若要删除的节点无孩子节点,可以归结到第二三种情况中。

查找最小的数:即为一直在左子树中寻找,具体实现为:

    k MinData()//找寻最左边小的数
    {
        assert(_pRoot);
        pNode pcur = _pRoot;
        while (pcur->_pLeft)
        {
            pcur = pcur->_pLeft;
        }
        return pcur->_key;
    }

查找最大的数:

    k maxData()//找寻最右边大的数
    {
        assert(_pRoot);
        pNode pcur = _pRoot;
        while (pcur->_pRight)
        {
            pcur = pcur->_pRight;
        }
        return pcur->_key;
    }

完整的代码如下:

#include<iostream>
#include<assert.h>
using namespace std;
template<class k,class v>
struct BSTreeNode
{
    BSTreeNode(const k&key, const v&value)
    :_pLeft(NULL)
    , _pRight(NULL)
    , _key(key)//要查找的值
    , _value(value)//数组的下标
    {}
    BSTreeNode<k, v>*_pLeft;
    BSTreeNode<k, v>*_pRight;
    k _key;
    v _value;
};
template<class k,class v>
class BSTree
{
public:
    typedef BSTreeNode<k, v>Node;
    typedef BSTreeNode<k, v>* pNode;
    BSTree()
        :_pRoot(NULL)
    {}
    void _CopyBinaryTee(pNode *pRoot)//创建二叉搜索树
    {
        pRoot = new Node(pRoot->_key, pRoot->_value);
         _CopyBinaryTee(&((*pRoot)->_pLeft));
         _CopyBinaryTee(&((*pRoot)->_pRight));
    }
    BSTree<k, v>& operator = (const BSTree<k, v>& bst)
    {
        if (this != &bt)
        {
            _DestoryBinaryTree(_pRoot);
            _pRoot = _CopyBinaryTree(bt._pRoot);
        }
        return *this;
    }
    void _DestoryBinaryTree(pNode pRoot)//销毁空间
    {
        if (pRoot)
        {
            _DestoryBinaryTree(pRoot->_pLeft);
            _DestoryBinaryTree(pRoot->_pRight);
            delete pRoot;
            pRoot = NULL;
        }
    }
    bool insert(const k&key, const v&value)//插入
    {
        if (_pRoot == NULL)
        {
            _pRoot = new Node(key, value);
            return true;
        }
        pNode pcur = _pRoot;
        pNode parent = NULL;
        //1.找到待插入的位置
        while (pcur)
        {
            if (key < pcur->_key)
            {
                parent = pcur;
                pcur = pcur->_pLeft;
            }
            else if (key > pcur->_key)
            {
                parent = pcur;
                pcur = pcur->_pRight;
            }
            else
                return false;
        }
        //2.插入新节点
        pcur = new Node(key, value);
        if (key < parent->_key)
        {
            parent->_pLeft = pcur;
        }
        if (key > parent->_key)
        {
            parent->_pRight = pcur;
        }
    }
    pNode Find(const k&key)//查找函数
    {
        pNode pcur = _pRoot;
        while (pcur)
        {
            if (key == pcur->_key)
            {
                return pcur;
            }
            else if (pcur->_key > key)
            {
                pcur = pcur->_pLeft;
            }
            else
            {
                pcur = pcur->_pRight;
            }
        }
        return NULL;
    }
    k MinData()//找寻最左边小的数
    {
        assert(_pRoot);
        pNode pcur = _pRoot;
        while (pcur->_pLeft)
        {
            pcur = pcur->_pLeft;
        }
        return pcur->_key;
    }
    k maxData()//找寻最右边大的数
    {
        assert(_pRoot);
        pNode pcur = _pRoot;
        while (pcur->_pRight)
        {
            pcur = pcur->_pRight;
        }
        return pcur->_key;
    }
    void Inorder()
    {
        return _Inorder(_pRoot);
    }
    void _Inorder(pNode pRoot)//中序
    {
        if (pRoot)
        {
            _Inorder(pRoot->_pLeft);
            cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;
            _Inorder(pRoot->_pRight);
        }
    }
    bool remove(const k&key)//删除
    {
            pNode parent = NULL;
            pNode pcur = _pRoot;
            //1.找到待删除的节点
            while (pcur)
            {
                if (pcur->_key > key)
                {
                    parent = pcur;
                    pcur = pcur->_pLeft;
                }
                else if (pcur->_key < key)
                {
                    parent = pcur;
                    pcur = pcur->_pRight;
                }
                else
                {
                    break;
                }
            }
            if (pcur)
            {
                if (pcur->_pLeft == NULL)//只有右子树
                {
                    if (pcur != _pRoot)
                    {
                        if (parent->_pLeft == pcur)
                            parent->_pLeft = pcur->_pRight;
                        else
                            parent->_pRight = pcur->_pRight;
                    }
                    else
                        _pRoot = pcur->_pRight;
                    delete pcur;
                    pcur = NULL;
                }
                else if (pcur->_pRight == NULL)//只有左子树
                {
                    if (pcur != _pRoot)
                    {
                        if (parent->_pLeft == pcur)
                            parent->_pLeft = pcur->_pLeft;
                        else
                            parent->_pRight = pcur->_pRight;
                    }
                    else
                        _pRoot = pcur->_pLeft;
                    delete pcur;
                    pcur = NULL;
                }
                else      //左右子树存在
                {
                    pNode parent = pcur;
                    pNode pDel = pcur->_pRight;//找到其右子树中序下的第一个节点
                    while (pDel->_pLeft)//找到其左子树
                    {
                        parent = pDel;
                        pDel = pDel->_pLeft;
                    }
                    pcur->_key = pDel->_key;
                    pcur->_value = pDel->_value;
                    if (parent->_pLeft == pDel)
                        parent->_pLeft = pDel->_pLeft;
                    else
                        parent->_pRight = pDel->_pRight;
                    delete pDel;
                    pDel = NULL;
                }
                return true;
            }
            return false;
        }
    //注:若要删除的节点无孩子节点,可以归结到第二三种情况中。
    ~BSTree()
    {
        _DestoryBinaryTree(_pRoot);
    }
private:
    pNode _pRoot;
}; 
int main()
{
    int arr[] = {5,3,4,1,7,8,2,6,0,9};
    BSTree<int, int>bst;
    for (int i = 0; i <10; i++)
    {
        bst.insert(arr[i], i);
    }
    bst.Inorder();
    cout << bst.Find(3)->_value << endl;
    cout << endl;
    bst.remove(7);
    bst.Inorder();
    cout << bst.MinData() << endl;
    cout << bst.maxData() << endl;
    system("pause");
    return 0;
}

验证结果为:

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值