二叉查找树BST

二叉查找树(BST)

定义:  

  又称二叉排序树,二叉搜索树;具备以下特性的树称为二叉查找树:

1.左子树上所有结点的值均小于它的根结点的值

2.右子树上所有结点的值均大于它的根结点的值;

3.左、右子树也分别为二叉查找树。

typedef struct STreeNode* pSTreeNode;
typedef int TreeKeyType;

struct STreeNode 
{
    TreeKeyType key;//节点数据
    //节点指针
    pSTreeNode pLeftChild;//指向左子树
    pSTreeNode pRightChild;//指向右子树
    
    STreeNode( TreeKeyType Value )//构造函数
    {
        key = Value;
        pLeftChild = NULL;
        pRightChild = NULL;
    }
    
};

查找:

1、若待查找的元素值和根节点相同,则返回根节点;
2、若待查找的元素值小于根节点的元素值,则递归从根节点的左子树中查找;
3、若待查找的元素值大于根节点的元素值,则递归从根节点的右子树中查找。

//查找成功,返回指向该节点的指针
//查找失败,返回NULL
//pNode-二叉查找树;Value-查找值
pSTreeNode Search( pSTreeNode pNode, TreeKeyType Value )
{
    //没有找到
    if ( pNode == NULL )
        return NULL;

    //待查找的元素值与根节点的值相同
    if ( pNode->key == Value )
        return pNode;

    else
    {
        //带查找的元素值小于根节点的元素值
        if ( pNode->key > Value )
            //在左子树中递归查找
            return Search( pNode->pLeftChild, Value );
        //带查找的元素值大于根节点的元素值
        else
            //在右子树中递归查找 
            return Search( pNode->pRightChild, Value );
    }
}

插入:

1、若当前二叉树为空,则插入的元素为根节点;
2、若插入的元素值小于根节点值,则递归从根节点的左子树中找到可插入位置;
3、若插入的元素值大于根节点值,则递归从根节点的右子树中找到可插入位置。

//插入成功返回true;插入失败返回false
//pNode-二叉查找树;Value-插入值
bool Insert( pSTreeNode pNode, TreeKeyType Value )
{
    if ( pNode == NULL)
            pNode = new STreeNode( Value );

    //插入元素的值小于根节点的值
    if ( pNode->key > Value )
        //插入到左子树
        Insert( pNode->pLeftChild, Value );

    //插入节点的值大于根节点的值
    else if( pNode->key < Value )
        //插入到右子树
        Insert( pNode->pRightChild, Value );  

    //插入节点的值等于根节点的值
    else   
        //树中已有关键字相同的节点,不再插入
        return false;

    return true;
}    

删除:

1、待删除节点Z为叶子节点,则直接删除该节点。修改父节点的指针;
2、待删除节点Z为单支节点(只有左子树或者右子树),让Z的子树与Z的父节点相连,删除节点Z;
3、待删除节点Z左右子树都不为空
方法一:找到Z的后继节点Y,Y一定没有左子树,用Y替换Z,并让Y的父亲节点成为Y的右子树的父亲节点,接着删除Y。
方法二:找到Z的前驱节点X,X一定没有右子树,用X替换Z,并让X的父亲节点成为X的左子树的父亲节点,接着删除X。

以方法二为例:

void CBinTree::Delete( pSTreeNode pNode,TreeKeyType Value )
{
    pSTreeNode pParentNode = pNode;
    pSTreeNode pFindNode = pNode;

    //循环结束后,pFindNode指向待删除节点
    //pParentNode指向待删除结点的父节点
    while ( pFindNode != NULL )
    {
        if ( pFindNode->key == Value )
            break;

        pParentNode = pFindNode;
        if ( pFindNode->key > Value )
            pFindNode = pFindNode->pLeftChild;
        else
            pFindNode = pFindNode->pRightChild;
    }

    //没有找到该节点,不需要做删除操作
    if ( pFindNode == NULL )
        return;


    //  该节点只有一棵子树或者为叶子节点
    if ( pFindNode->pLeftChild == NULL || pFindNode->pRightChild == NULL )
    {
        //  该节点为叶子节点
        pSTreeNode pTemp = NULL;

        //该节点只有左子树
        if ( pFindNode->pLeftChild != NULL)
            pTemp = pFindNode->pLeftChild;

        //该节点只有右子树
        else if ( pFindNode->pRightChild != NULL )
            pTemp = pFindNode->pRightChild;


        //该节点为其父节点的左孩子
        if ( pParentNode->pLeftChild == pFindNode )
            //将该节点的子树变为其父节点的左子树
            pParentNode->pLeftChild = pTemp;

        //该节点为其父节点的有孩子
        else
            //将该节点的子树变为其父节点的右子树
            pParentNode->pRightChild = pTemp;

        delete pFindNode;
        pFindNode = NULL;
    }


    //该节点的左右子树均不为空
    else
    {
        pSTreeNode pTemp = pFindNode->pLeftChild;
        pSTreeNode pTempParent = pFindNode;

        //循环找到该节点左子树的右侧尽头的节点
        //即待删除节点的前驱节点pTemp(中序遍历的前驱)
        //该节点的前驱节点为左子树中关键字值最大的节点
        while ( pTemp->pRightChild != NULL )
        {
            pTempParent = pTemp;//前驱结点的父节点
            pTemp = pTemp->pRightChild; //一直往右下方走
        }

        pFindNode->key = pTemp->key;//pTemp替换pFindNode
        pTempParent->pRightChild = pTemp->pLeftChild;

        delete pTemp;
        pTemp = NULL;
    }
}

遍历:

1、前序遍历(递归):先根节点,后左孩子节点,再右孩子结点。
2、中序遍历(递归):先左孩子结点,后根节点,再右孩子结点。
3、后序遍历(递归):先做孩子节点,后右孩子结点,再根节点。

//前序遍历
void CBinTree::PreorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    cout << " " << pNode->key << " ";
    PreorderRecursively( pNode->pLeftChild );//左子树
    PreorderRecursively( pNode->pRightChild );//右子树
}

//中序遍历
void CBinTree::InorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    InorderRecursively( pNode->pLeftChild );
    cout << " " << pNode->key << " ";
    InorderRecursively( pNode->pRightChild );
}

//后序遍历
void CBinTree::PostorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    PostorderRecursively( pNode->pLeftChild );
    PostorderRecursively( pNode->pRightChild );
    cout << " " << pNode->key << " ";
}

原文链接 https://blog.csdn.net/lining0420/article/details/76167901

原文地址:https://www.cnblogs.com/yongjin-hou/p/14533790.html