二叉搜索树

二叉搜索树定义

1.每个结点都有一个作为搜索依据的关键码,所有结点的关键码都不相同。
2.左子树上所有结点的关键码都小于根节点的关键码。
3.右子树上所有结点的关键码都大于根节点的关键码。
4.左子树和右子树也是二叉搜索树。

二叉搜索树实现

使用c++实现二叉搜索树,这些是必要的声明。

#include <iostream>
#include <stack>
using namespace std;
template <class Type> class BST;    //二叉搜索树的前向声明

首先给出二叉搜索树的结点数据结构,和普通树的结点类相同。

template <class Type>
class BstNode
{
    template <class T>
    friend  class BST;    //BST需要访问私有成员data

public:
    //构造函数
    BstNode() : leftChild( NULL ), rightChild( NULL ) {}
    BstNode( const Type d = 0, BstNode* L = NULL, BstNode* R = NULL )
        : data( d ), leftChild( L ), rightChild( R ) {}

    ~BstNode() {}
    //Type get_data() { return data; }//测试中用到
protected:
    Type data;  //结点数据域
    BstNode<Type>* leftChild, *rightChild;
};

二叉搜索树的抽象数据类型。

template <class Type>
class BST
{
public:
    BST() : root( NULL ) {}
    BST( Type value );     //指定输入结束符的构造函数
    ~BST() { MakeEmpty( root ); }
    void MakeEmpty() { MakeEmpty( root ); root = NULL; }
    void PrintTree() { PrintTree( root ); }
    int Find( const Type&x ) const { return Find( x, root ) != NULL; }
    Type Min();
    Type Max();
    void Insert( const Type &x ) { Insert( x, root ); };
    void Remove( const Type &x) { Remove( x, root ); };

private:
    void MakeEmpty( BstNode<Type>*& ptr );      //将以ptr为根节点的二叉树置空
    void Insert( const Type& x, BstNode<Type>*& ptr );      //插入
    void Remove( const Type& x, BstNode<Type>*& ptr );      //删除
    void PrintTree( BstNode<Type>* ptr ) const;
    BstNode<Type>* Copy( const BstNode<Type>* ptr );        //复制
    BstNode<Type>* Find( const Type& x, BstNode<Type> *ptr ) const;     //搜索
    BstNode<Type>* Min( BstNode<Type>* ptr ) const;         //最小元素
    BstNode<Type>* Max( BstNode<Type>* ptr ) const;         //最大元素

private:
    BstNode<Type>* root;    //二叉搜索树的根节点
    Type refValue;          //数据输入停止标识

};

构造函数:从标准输入构造二叉搜索树,直到遇到输入停止标识


template <class Type>
BST<Type>::BST( Type value )
    : refValue( value ), root( NULL )
{
    Type x;
    //重载>>
    cin >> x;
    //Type 需要重载!=,否则这块会失效
    while ( x != refValue )
    {
        Insert( x, root );
        cin >> x;
    }
}

二叉搜索树置空:
MakeEmpty()删除参数中传入的结点,使用MakeEmpty()递归删除二叉搜索树种的每个结点。


//递归实现
template <class Type>
void BST<Type>::MakeEmpty( BstNode<Type>*& ptr )
{
    if ( ptr == NULL )
        return ;
    if ( ptr->leftChild == NULL && ptr->rightChild == NULL )
    {
        delete ptr;
        ptr = NULL;
        return ;
    }
    else if ( ptr->leftChild != NULL )
        MakeEmpty( ptr->leftChild );
    else
        MakeEmpty( ptr->rightChild );
}

二叉搜索树中查找元素

template <class Type>
BstNode<Type>* BST<Type>::Find( const Type& x, BstNode<Type>* ptr ) const
{
    while ( ptr != NULL )
    {
        if ( ptr->data == x )
            return ptr;
        if ( x > ptr->data )
            ptr = ptr->rightChild;
        else
            ptr = ptr->leftChild;
    }
    return ptr;
}

删除结点:递归实现,容易理解,容易实现

//删除结点的递归实现
//相对于非递归实现轻松许多
template <class Type>
void BST<Type>::Remove( const Type& x, BstNode<Type>*& ptr )
{
    if ( ptr == NULL )
        return ;
    if ( ptr->data == x )
    {
        if ( ptr->leftChild == NULL && ptr->rightChild == NULL )
        {
            delete ptr;
            ptr = NULL;
            return ;
        }
        else if ( ptr->leftChild == NULL )
        {
            BstNode<Type>* temp = ptr;
            ptr = ptr->rightChild;
            delete temp;
            return ;
        }
        else if ( ptr->rightChild == NULL )
        {
            BstNode<Type>* temp = ptr;
            ptr = ptr->leftChild;
            delete temp;
            return ;
        }
        else
        {
            ptr->data = Min( ptr->rightChild )->data;
            Remove( ptr->data, ptr->rightChild );
        }
    }
    else if ( x > ptr->data )
    {
        Remove( x, ptr->rightChild );
    }
    else
    {
        Remove( x, ptr->leftChild );
    }

}

删除结点:非递归实现,要考虑各种特殊情况,理解麻烦


//删除结点的非递归实现
//非递归实现比较麻烦
template <class Type>
void BST<Type>::Remove( const Type& x, BstNode<Type>*& ptr )
{

    BstNode<Type>* fp = ptr;
    BstNode<Type>* p = ptr;
    //如果是删除根节点要特殊处理,麻烦
    if ( ptr->data == x )
    {
        if ( ptr->leftChild == NULL && ptr->rightChild == NULL )
        {
            delete ptr;
            ptr = NULL;
            return ;
        }
        else if ( ptr->leftChild == NULL )
        {
            BstNode<Type>* temp = ptr;
            ptr = temp->rightChild;
            delete temp;
            return ;
        }
        else if ( ptr->rightChild == NULL )
        {
            BstNode<Type>* temp = ptr;
            ptr = temp->leftChild;
            delete temp;
            return ;
        }
        else
        {
            ptr->data = Min(ptr->rightChild)->data;
            Remove( ptr->data, ptr->rightChild );
            return ;
        }
    }
    while ( p != NULL )
    {
        //找到目标,进行删除
        if ( x == p->data )
        {
            BstNode<Type>* temp = p;
            if ( p->leftChild == NULL )
            {
                //左孩子和右孩子同时为空,直接删除即可
                if ( p->rightChild == NULL )
                {
                    if ( p->data > fp->data )
                        fp->rightChild = NULL;
                    else
                        fp->leftChild = NULL;
                    delete p;
                }
                //左孩子为空,右孩子不为空,将右孩子替代根节点
                else
                {
                    if ( p->data > fp->data )
                        fp->rightChild = p->rightChild;
                    else
                        fp->leftChild = p->rightChild;
                    delete p;
                }
            }
            //左孩子不为空,右孩子为空,将左孩子替代根节点
            else if ( p->rightChild == NULL )
            {
                if ( p->data > fp->data )
                    fp->rightChild = p->leftChild;
                else
                    fp->leftChild = p->leftChild;
                delete p;
            }
            //左孩子和右孩子都不为空,选择右孩子中最小的元素替代根节点
            else
            {
                //将p的键值改成p的右子树中最小的那个键值
                p->data = Min( p->rightChild )->data;
                //调用自己删除p的右子树中键值最小的那个结点
                Remove( p->data, p->rightChild );
            }
        }
        else if ( x > p->data )
        {
            fp = p;
            p = p->rightChild;
        }
        else
        {
            fp = p;
            p = p->leftChild;
        }

    }
}

求二叉搜索树键最小的结点


template <class Type>
BstNode<Type>* BST<Type>::Min(BstNode<Type>* ptr) const
{
    if ( ptr == NULL )
        return NULL;
    while ( ptr->leftChild != NULL )
    {
        ptr = ptr->leftChild;
    }
    return ptr;
}
template <class Type>
Type BST<Type>::Min()
{
    BstNode<Type>* result = Min( root );
    if ( result == NULL )
        return refValue;
    else
        return result->data;
}

求二叉搜索树键值最大的结点

template <class Type>
Type BST<Type>::Max()
{
    BstNode<Type>* result = Max( root );
    if ( result == NULL )
        return refValue;
    else
        return result->data;
}

template <class Type>
BstNode<Type>* BST<Type>::Max( BstNode<Type>* ptr ) const
{
    if ( ptr == NULL )
        return NULL;
    while ( ptr->rightChild != NULL )
    {
        ptr = ptr->rightChild;
    }
    return ptr;
}

插入,


//迭代实现
template <class Type>
void BST<Type>::Insert(const Type& x, BstNode<Type>*& ptr)
{
    //若根节点为空,直接插入到根节点位置
    if ( ptr == nullptr )
    {
        ptr = new BstNode<Type>( x );
        return ;
    }
    //fp 插入点的父结点 p 未来的插入点
    BstNode<Type>* p = ptr;
    BstNode<Type>* fp = ptr;
    //找到插入点
    while ( p != nullptr )
    {
        fp = p;
        if ( x > p->data  )
            p = p->rightChild;
        else if ( x <= p->data )
            p = p->leftChild;
    }
    //构造新结点
    p = new BstNode<Type>( x );
    //判断新节点是左子树还是右子树并且插入
    if ( x > fp->data )
        fp->rightChild = p;
    else
        fp->leftChild = p;
}

打印二叉搜索树并输出,即非递归实现二叉树的中序遍历


//中序遍历二叉搜索树
template <class Type>
void BST<Type>::PrintTree( BstNode<Type>* ptr ) const
{
    if ( ptr == NULL )
        return ;
    //上一次对栈的操作是push还是pop
    //用这个解决回溯时不能确定左子树是否被访问过的问题
    //如果上一次对栈是push操作,说明栈顶部是一个新结点,新结点的左子树肯定没有被访问过
    //如果上一次是pop操作,说明栈顶的元素的左子树已经被访问过了
    bool pre_is_push = true;
    stack<BstNode<Type>*> mid_order_stack;      //迭代实现中序遍历二叉搜索树辅助栈
    mid_order_stack.push( ptr );
    while ( !mid_order_stack.empty() )
    {
        //show_stack( stack<BstNode<Type>*>( mid_order_stack ) );//脚手架 显示栈内容
        //cout << mid_order_stack.top()->data << endl;//显示栈顶元素
        if ( pre_is_push && mid_order_stack.top()->leftChild != NULL )
        {
            ptr = mid_order_stack.top()->leftChild;
            mid_order_stack.push( ptr );
            pre_is_push = true;
        }
        else
        {
            BstNode<Type>* temp_mid = mid_order_stack.top();
            mid_order_stack.pop();
            pre_is_push = false;
            if ( temp_mid->rightChild != NULL )
            {
                mid_order_stack.push( temp_mid->rightChild );
                pre_is_push = true;
            }
            cout << temp_mid->data << " ";
        }
    }
    cout << endl;
}

测试主函数

int main( void )
{
    BST<int> int_bstree( 0 );
    cout << int_bstree.Max() << endl;
    cout << int_bstree.Min() << endl;
    int_bstree.PrintTree();
    int_bstree.Remove( 67 );
    cout << int_bstree.Find( 5 ) << endl;
    cout << int_bstree.Find( 100 ) << endl;
    int_bstree.PrintTree();
    int_bstree.MakeEmpty();
    int_bstree.PrintTree();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值