数据结构-----二叉搜索树

一、基本概念
1、二叉搜索树概念
二叉搜索树:又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
(1)若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
(2)若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
(3)它的左右子树也分别为二叉搜索树
2、形式
这里写图片描述
二、操作
(一)插入
1、若二叉树为空——>直接插入
2、不为空
(1)找插入结点的位置
(2)插入结点
注:新插入的结点为叶子结点,若插入的结点在树中已经存在,则插入失败
程序算法如下所示:

bool Insert(const K& key, const V& value)
    {
        pNode pCur = _pRoot;
        pNode pParent = NULL;
        pNode pNewNode = new Node(key, value);
        //空树--直接插入
        if (pCur == NULL)
        {
            _pRoot = pNewNode;
            return true;
        }

        //找插入的位置
        while (pCur)
        {
            if (key == pCur->_key)
                return false;
            else if (key < pCur->_key)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
        }
        //插入元素
        if (key < pParent->_key)
            pParent->_pLeft = pNewNode;
        else
            pParent->_pRight = pNewNode;

        return true;
    }

递归实现

bool _Insert1(pNode& pRoot, const K&key, const V&value)
    {
        pNode pNewNode = new Node(key, value);
        if (pRoot == NULL)
        {
            pRoot = pNewNode;
            return true;
        }

        if (pRoot == NULL)
            return false;
        if (pNewNode->_key == pRoot->_key)
            return false;

        if (pRoot->_key > pNewNode->_key)
            _Insert1(pRoot->_pLeft, key, value);

        else
            _Insert1(pRoot->_pRight, key, value);
    }

(二)查找
1、空树—–则此结点不存在
2、非空树
(1)用当前结点与所需比较的结点比较,如果大于,则走右子树,反之,查找成功。
程序算法如下所示

bool Find(const K&key)
    {
        //空树
        if (_pRoot == NULL)
            return false;
        //非空树
        pNode pCur = _pRoot;
        while (pCur)
        {
            if (key == pCur->_key)
                return true;
            else if (key > pCur->_key)
                pCur = pCur->_pRight;
            else
                pCur = pCur->_pLeft;
        }
        return false;
    }

递归实现

bool _Find1(pNode pRoot, const K&key)
    {
        if (pRoot == NULL)
            return false;       
        if (key == pRoot->_key)
            return true;
        //左子树
        else if (key < pRoot->_pLeft->_key)
            _Find1(pRoot->_pLeft, key);
        //右子树
        else
            _Find1(pRoot->_pRight,key);
    }

(三)获取最小的元素
二叉搜索树是一个有序树,最小的结点位于树中的最左边,因此,直到最左边没有元素,则找到最小的一个结点。
程序算法如下所示:

K LastMost()const
    {
        assert(_pRoot);//判断是否为空树

        pNode pCur = _pRoot;
        while (pCur->_pLeft)
        {
            pCur = pCur->_pLeft;
        }
        return pCur->_key;
    }

(四)获取最大的元素
二叉搜索树是一个有序树,最大的结点位于树中的最右边,因此,直到最右边没有元素,则找到最大的一个结点。
程序算法如下所示:

    K RightMost()const
    {
        assert(_pRoot);//判断是否为空树

        pNode pCur = _pRoot;
        while (pCur->_pRight)
        {
            pCur = pCur->_pRight;
        }
        return pCur->_key;
    }

(五)删除树中的元素
树存在,主要分四种情况,其中,情况一与二或三可以合并在一起
1、删除叶子结点——>直接删
2、待删的结点只有左孩子
3、待删的结点只有右孩子
4、待删的结点左右孩子均有
这里写图片描述
这里写图片描述
这里写图片描述
删除情况具体如上面所示,根据上面的情况,便可完成所有的情况,具体代码如下所示:

void Pop(const K&key)
    {
        //空树
        if (_pRoot == NULL)
            return;
        //非空树
        pNode pDel = _pRoot;
        pNode pDParent = NULL;
        //找待删除的结点
        while (pDel)
        {
            if (key == pDel->_key)
                break;
            else if (key > pDel->_key)
            {
                pDParent = pDel;
                pDel = pDel->_pRight;
            }
            else
            {
                pDParent = pDel;
                pDel = pDel->_pLeft;
            }
        }
        //删除的结点不在树中
        if (pDel == NULL)
        {
            return;
        }

        //删除结点
        //只有左孩子,此种情况包含两个孩子都没有
        if (NULL == pDel->_pRight)
        {
            //判断待删结点是否为根节点
            if (pDel == _pRoot)//左单支
            {
                _pRoot = pDel->_pLeft;

            }
            else
            {
                //待删结点在双亲结点的左孩子上
                if (pDParent->_pLeft == pDel)
                {
                    pDParent->_pLeft = pDel->_pLeft;

                }
                //待删结点在双亲结点的右孩子上
                else
                {
                    pDParent->_pRight = pDel->_pLeft;

                }
            }
        }

        //只有右孩子,此种情况包含两个孩子都没有
        else if (NULL == pDel->_pLeft)
        {
            if (pDel == _pRoot)//右单支
            {
                _pRoot = pDel->_pRight;

            }
            else
            {
                if (pDParent->_pLeft == pDel)
                {
                    pDParent->_pLeft = pDel->_pRight;

                }
                else
                {
                    pDParent->_pRight = pDel->_pRight;

                }
            }
        }
        //两个孩子都有
        else
        {
            //找替代结点,在右子树中,找待删除结点的中序遍历下的第一个结点,右子树中序遍历下的第一个结点
            pNode pReplaceNode = pDel->_pRight;
            pDParent = pDel;
            //找出替代结点
            while (pReplaceNode->_pLeft)
            {
                pDParent = pReplaceNode;
                pReplaceNode = pReplaceNode->_pLeft;
            }
            //交换待删结点与替代结点,一般的替代结点为只有右子树或者叶子结点
            pDel->_key = pReplaceNode->_key;
            pDel->_value = pReplaceNode->_value;
            pDel = pReplaceNode;
            //删除结点

            if (pDParent->_pLeft == pDel)
            {
                pDParent->_pLeft = pDel->_pRight;
            }
            else
            {
                pDParent->_pRight = pDel->_pRight;
            }
        }
        delete pDel;
    }

二叉搜索树最大的特点就是,其中序遍历的结果是一个有序的结果。

对于二叉搜索树,有关的操作就是在上面了,希望大家一起进步!!
所有的代码如下所示:

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
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
{
    typedef BSTreeNode<K, V> Node;
    typedef BSTreeNode<K, V>* pNode;
public:
    BSTree()
        :_pRoot(NULL)
    {}
    bool Insert(const K& key, const V& value)
    {
        pNode pCur = _pRoot;
        pNode pParent = NULL;
        pNode pNewNode = new Node(key, value);
        //空树--直接插入
        if (pCur == NULL)
        {
            _pRoot = pNewNode;
            return true;
        }
        //找插入的位置
        while (pCur)
        {
            if (key == pCur->_key)
                return false;
            else if (key < pCur->_key)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
        }
        //插入元素
        if (key < pParent->_key)
            pParent->_pLeft = pNewNode;
        else
            pParent->_pRight = pNewNode;
        return true;
    }
    //递归
    void Insert1(const K& key, const V& value)
    {
        _Insert1(_pRoot, key, value);
    }
    //查找某一个元素
    bool Find(const K&key)
    {
        //空树
        if (_pRoot == NULL)
            return false;
        //非空树
        pNode pCur = _pRoot;
        while (pCur)
        {
            if (key == pCur->_key)
                return true;
            else if (key > pCur->_key)
                pCur = pCur->_pRight;
            else
                pCur = pCur->_pLeft;
        }
        return false;
    }
    //递归
    bool Find1(const K&key)
    {
        //空树
        if (_pRoot == NULL)
            return true;
        //非空树
        _Find1(_pRoot, key);
    }
    //获取最小的元素,一直往其左边走
    K LastMost()const
    {
        assert(_pRoot);//判断是否为空树
        pNode pCur = _pRoot;
        while (pCur->_pLeft)
        {
            pCur = pCur->_pLeft;
        }
        return pCur->_key;
    }

    //获取最大的元素
    K RightMost()const
    {
        assert(_pRoot);//判断是否为空树

        pNode pCur = _pRoot;
        while (pCur->_pRight)
        {
            pCur = pCur->_pRight;
        }
        return pCur->_key;
    }

    void Pop(const K&key)
    {
        //空树
        if (_pRoot == NULL)
            return;
        //非空树
        pNode pDel = _pRoot;
        pNode pDParent = NULL;
        //找待删除的结点
        while (pDel)
        {
            if (key == pDel->_key)
                break;
            else if (key > pDel->_key)
            {
                pDParent = pDel;
                pDel = pDel->_pRight;
            }
            else
            {
                pDParent = pDel;
                pDel = pDel->_pLeft;
            }
        }
        //删除的结点不在树中
        if (pDel == NULL)
            return;
        //删除结点
        //只有左孩子,此种情况包含两个孩子都没有
        if (NULL == pDel->_pRight)
        {
            //判断待删结点是否为根节点
            if (pDel == _pRoot)//左单支
            {
                _pRoot = pDel->_pLeft;              
            }
            else
            {
                //待删结点在双亲结点的左孩子上
                if (pDParent->_pLeft == pDel)
                {
                    pDParent->_pLeft = pDel->_pLeft;                    
                }
                //待删结点在双亲结点的右孩子上
                else
                {
                    pDParent->_pRight = pDel->_pLeft;           
                }
            }
        }
        //只有右孩子,此种情况包含两个孩子都没有
        else if (NULL == pDel->_pLeft)
        {
            if (pDel == _pRoot)//右单支
            {
                _pRoot = pDel->_pRight;

            }
            else
            {
                if (pDParent->_pLeft == pDel)
                {
                    pDParent->_pLeft = pDel->_pRight;               
                }
                else
                {
                    pDParent->_pRight = pDel->_pRight;                  
                }
            }
        }
        //两个孩子都有
        else
        {
            //找替代结点,在右子树中,找待删除结点的中序遍历下的第一个结点,右子树中序遍历下的第一个结点
            pNode pReplaceNode = pDel->_pRight;
            pDParent = pDel;
            //找出替代结点
            while (pReplaceNode->_pLeft)
            {
                pDParent = pReplaceNode;
                pReplaceNode = pReplaceNode->_pLeft;
            }
            //交换待删结点与替代结点,一般的替代结点为只有右子树或者叶子结点
            pDel->_key = pReplaceNode->_key;
            pDel->_value = pReplaceNode->_value;
            pDel = pReplaceNode;
            //删除结点

            if (pDParent->_pLeft == pDel)
            {
                pDParent->_pLeft = pDel->_pRight;
            }
            else
            {
                pDParent->_pRight = pDel->_pRight;
            }
        }
        delete pDel;
    }
    void InOrder()
    {
        cout << "InOrder:" << endl;
        _InOrder(_pRoot);
    }
    //递归
private:
    bool _Find1(pNode pRoot, const K&key)
    {
        if (pRoot == NULL)
            return false;       
        if (key == pRoot->_key)
            return true;
        //左子树
        else if (key < pRoot->_pLeft->_key)
            _Find1(pRoot->_pLeft, key);
        //右子树
        else
            _Find1(pRoot->_pRight,key);
    }

    bool _Insert1(pNode& pRoot, const K&key, const V&value)
    {
        pNode pNewNode = new Node(key, value);
        if (pRoot == NULL)
        {
            pRoot = pNewNode;
            return true;
        }

        if (pRoot == NULL)
            return false;
        if (pNewNode->_key == pRoot->_key)
            return false;

        if (pRoot->_key > pNewNode->_key)
            _Insert1(pRoot->_pLeft, key, value);

        else
            _Insert1(pRoot->_pRight, key, value);
    }
private:
    void _InOrder(pNode pRoot)
    {
        if (pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;;
            _InOrder(pRoot->_pRight);
        }

    }

主要测试代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
#include"BinarySearchTree.hpp"

int main()
{
    int a[] = { 5, 7, 2, 1, 9, 4, 8, 3, 6, 0 };
    BSTree<int,int> bst1;
    for (int i = 0; i < sizeof(a) / sizeof(*a); ++i)
    {
        bst1.Insert(a[i], a[i]);

    }
    bst1.InOrder();

    for (int i = 0; i < sizeof(a) / sizeof(*a); ++i)
    {
        bst1.Insert1(a[i], a[i]);

    }
    bst1.InOrder();
    if (bst1.Find(10))
        cout << "存在" << endl;
    else
        cout << "不存在" << endl;

    if (bst1.Find(5))
        cout << "存在" << endl;
    else
        cout << "不存在" << endl;

    if (bst1.Find1(10))
        cout << "存在" << endl;
    else
        cout << "不存在" << endl;

    if (bst1.Find1(5))
        cout << "存在" << endl;
    else
        cout << "不存在" << endl;

    cout << bst1.LastMost() << " ";//最小
    cout << bst1.RightMost();//最大
    //删除根结点
    bst1.Pop(5);
    bst1.InOrder();
    //删除结点只有右子树
    bst1.Pop(7);
    bst1.InOrder();
    //删除叶子结点
    bst1.Pop(0);
    bst1.InOrder();
    //删除结点只有左子树
    bst1.Pop(4);
    bst1.InOrder();
    //待删结点的左右孩子均存在
    bst1.Pop(2);
    bst1.InOrder();
    //删除结点不存在
    bst1.Pop(2);
    bst1.InOrder();
    //bst1.Pop(9);
    //bst1.InOrder();
    //bst1.Pop(2);
    //bst1.InOrder();
    //bst1.Pop(3);
    //bst1.InOrder();
    //bst1.Pop(6);
    //bst1.InOrder();
    //bst1.Pop(1);
    //bst1.InOrder();
    空树
    //bst1.Pop(2);
    //bst1.InOrder();
    //判断空树的情况
    //BSTree<int, int> bst2;
    //cout << bst2.LastMost() << " ";//最小
    //cout << bst2.RightMost();//最大
    system("pause");
    return 0;
}

只有不停的奔跑,才能不停留在原地。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值