二叉搜索树的初始化、插入、删除、查找、销毁等操作

二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一颗空树,或者是具有以下性质的二叉树:

  1. 若它的左子树不为空,则左子树上所有结点的值都小于根结点的值
  2. 若它的右子树不为空,则右子树上所有结点的值都大于根结点的值
  3. 它的左右子树也分别为二叉搜索树
    例:
    《二叉搜索树的初始化、插入、删除、查找、销毁等操作》
    我们要实现这些操作。先定义一个二叉搜索树的结构体,这个结构体成员包括左右孩子两个指针,还有它的数据:
typedef int BSDataType;
typedef struct BSTreeNode
{
    struct BSTreeNode* _pLeft;
    struct BSTreeNode* _pRight;
    BSDataType _data;
}BSTNode;

二叉搜索树的初始化:
需要传入二级指针,因为要改变根结点的指向,让根结点指向空

void InitBSTree(BSTNode** pRoot)
{
    assert(pRoot);
    *pRoot = NULL;
}

二叉搜索树的插入:
分析:

  1. 树为空,则直接插入(这也是传二级指针的原因,因为要改变根结点的指向)
    《二叉搜索树的初始化、插入、删除、查找、销毁等操作》
    2.树不空,按二叉搜索树性质查找插入位置,插入新结点

非递归代码:

bool InsertBSTree(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    if (*pRoot == NULL)
    {
        (*pRoot) = BuyBSTNode(data);
        return true;
    }
    else
    {
        BSTNode* pCur = (*pRoot);
        BSTNode *pParent = NULL;
        //找到插入结点的位置
        while (pCur)
        {
            pParent = pCur;
            if (pCur->_data == data)//如果当前结点=要插入的结点,则退出,因为这个元素已经存在
            {
                return false;
            }
            else if (pCur->_data > data)//如果当前结点数>要插入的数,向当前结点的左子树去找插入位置
            {
                pCur = pCur->_pLeft;
            }
            else//如果当前结点数<要插入的数,向当前结点的右子树去找插入位置
            {
                pCur = pCur->_pRight;
            }
        }
        //插入新结点
        if (data > pParent->_data)//如果插入的元素比它要插入位置的元素大,则要插入的元素应该是要插入位置结点的右孩子
        {
            pParent->_pRight = BuyBSTNode(data);
            return true;
        }
        if (data < pParent->_data)//如果插入的元素比它要插入位置的元素小,则要插入的元素应该是要插入位置结点的左孩子
        {
            pParent->_pLeft = BuyBSTNode(data);
            return true;
        }
    }
    return false;
}

递归代码:

bool InsertBSTreeNor(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    if (NULL == *pRoot)
        *pRoot = BuyBSTNode(data);
    else
    {
        if (data == (*pRoot)->_data)
        {
            return false;
        }
        else if (data < (*pRoot)->_data)
            return InsertBSTree(&(*pRoot)->_pLeft, data);
        else
            return InsertBSTree(&(*pRoot)->_pRight, data);

    }
    return true;
}

二叉搜索树的删除:
分析:
删除的话就有点复杂了,因为删除结点的位置不同,我们处理的方式不同。
首先查找元素是否在二叉搜索树中,如果不存在,则返回,否则要删除的结点可能分下面四种情况:
1.要删除的结点无孩子结点
2.要删除的结点只有左孩子结点
3.要删除的结点只有右孩子
4.要删除的结点有左、有结点
《二叉搜索树的初始化、插入、删除、查找、销毁等操作》
非递归代码:

bool DelectBSTree(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    BSTNode* pCur = NULL;
    BSTNode* pParent = NULL;
    if (NULL == *pRoot)
        return false;
    else
    {
        //找到待删除结点

        pCur = *pRoot;
        while (pCur)
        {
            if (data > pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else if (data < pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else
                break;
        }
        //删除结点

        //待删结点是叶子节点或者只有右孩子
        if (NULL == pCur->_pLeft)
        {
            if (pCur == *pRoot)//若果删除的是根结点
                *pRoot = pCur->_pRight;
            else if (pCur == pParent->_pLeft)
                pParent->_pLeft = pCur->_pRight;
            else
                pParent->_pRight = pCur->_pRight;
        }
        //只有左孩子
        else if (NULL == pCur->_pRight)
        {
            if (pCur == *pRoot)//若果删除的是根结点
                *pRoot = pCur->_pLeft;
            else if (pCur == pParent->_pLeft)
                pParent->_pLeft = pCur->_pLeft;
            else
                pParent->_pRight = pCur->_pLeft;
        }
        //左右孩子都存在
        else
        {
            //替代法,向待删除点的右子树找最左边的数(最小)/向待删除点的左子树找最右边的数(最大),将待删除点与最左边/最右边的数交换,删除最左边/最右边的数
            BSTNode* Inorder = pCur->_pRight;

            while (Inorder->_pLeft)//除了循环函数,Inorder不可能有左孩子
            {
                pParent = Inorder;
                Inorder = Inorder->_pLeft;
            }
            pCur->_data = Inorder->_data;//交换
            if (Inorder == pParent->_pLeft)
                pParent->_pLeft = Inorder->_pRight;
            else if (Inorder == pParent->_pRight)
                pParent->_pRight = Inorder->_pRight;
            pCur = Inorder;
        }
    }
    free(pCur);
    pCur = NULL;
    return true;
}

递归代码:

bool DelectBSTreeNor(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);

    if (NULL == *pRoot)
        return false;
    else
    {

        if (data > (*pRoot)->_data)
        {
            return DelectBSTreeNor(&(*pRoot)->_pRight, data);
        }
        else if (data < (*pRoot)->_data)
        {
            return DelectBSTreeNor(&(*pRoot)->_pLeft, data);
        }
        else //data == (*pRoot)->_data
        {
            //这时已经找到了待删除结点
            BSTNode* pDel = *pRoot;
            if (NULL == pDel->_pLeft)
            {
                *pRoot = pDel->_pRight;
                free(pDel);
                return true;
            }
            else if (NULL == (*pRoot)->_pRight)
            {
                *pRoot = pDel->_pLeft;
                free(pDel);
                return true;
            }
            else //左右孩子都存在
            {
                BSTNode* Inorder = pDel->_pRight;
                while (Inorder->_pLeft)
                    Inorder = Inorder->_pLeft;
                pDel->_data = Inorder->_data;
                return DelectBSTreeNor(&(*pRoot)->_pRight, pDel->_data);
            }
        }
    }
}

二叉搜索树的查找:
我们根据二叉搜索树的性质可以得出,如果要找的数据比当前根结点的数据小,我们应该往当前根结点的左子树去找,如果比当前根结点的数据大,往当前根结点的右子树去找。

非递归代码:

BSTNode* FindBSTree(BSTNode* pRoot, BSDataType data)
{
    BSTNode* pCur = NULL;
    if (NULL == pRoot)
        return NULL;

    pCur = pRoot;
    while (pCur)
    {
        if (pCur->_data == data)
        {
            return pCur;
        }
        else if (pCur->_data > data)
        {
            pCur = pCur->_pLeft;
        }
        else
        {
            pCur = pCur->_pRight;
        }
    }
    return NULL;
}

递归代码:


BSTNode* FindBSTreeNor(BSTNode* pRoot, BSDataType data)
{
    if (NULL == pRoot)
        return NULL;
    else if (data == pRoot->_data)
        return pRoot;
    else if (data < pRoot->_data)
        return FindBSTreeNor(pRoot->_pLeft, data);
    else
        return FindBSTreeNor(pRoot->_pRight, data);

}

下面是完整的代码:
BSTree.h

#ifndef __BSTREE_H__
#define __BSTREE_H__

#include<stdio.h>
#include<assert.h>
#include<malloc.h>
#define bool int
#define true 1
#define false 0

typedef int BSDataType;
typedef struct BSTreeNode
{
    struct BSTreeNode* _pLeft;
    struct BSTreeNode* _pRight;
    BSDataType _data;
}BSTNode;

void InitBSTree(BSTNode** pRoot);
bool InsertBSTree(BSTNode** pRoot, BSDataType data);
bool InsertBSTreeNor(BSTNode** pRoot, BSDataType data);
bool DelectBSTree(BSTNode** pRoot, BSDataType data);
bool DelectBSTreeNor(BSTNode** pRoot, BSDataType data);
BSTNode* FindBSTree(BSTNode* pRoot, BSDataType data);
BSTNode* FindBSTreeNor(BSTNode* pRoot, BSDataType data);
void DestroyBSTree(BSTNode** pRoot);

#endif //__BSTREE_H__ 

BSTree.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"BSTree.h"

void InitBSTree(BSTNode** pRoot)
{
    assert(pRoot);
    *pRoot = NULL;
}

BSTNode* BuyBSTNode(BSDataType data)
{
    BSTNode* newNode = (BSTNode*)malloc(sizeof(BSTNode));
    if (NULL == newNode)
    {
        printf("创建节点失败\n");
        return NULL;
    }
    newNode->_data = data;
    newNode->_pLeft = NULL;
    newNode->_pRight = NULL;
    return newNode;
}

void InOrder(BSTNode* pRoot)
{
    if (NULL == pRoot)
        return;
    InOrder(pRoot->_pLeft);
    printf("%d ", pRoot->_data);
    InOrder(pRoot->_pRight);
}

bool InsertBSTree(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    if (*pRoot == NULL)
    {
        (*pRoot) = BuyBSTNode(data);
        return true;
    }
    else
    {
        BSTNode* pCur = (*pRoot);
        BSTNode *pParent = NULL;
        //找到插入结点的位置
        while (pCur)
        {
            pParent = pCur;
            if (pCur->_data == data)//如果当前结点=要插入的结点,则退出,因为这个元素已经存在
            {
                return false;
            }
            else if (pCur->_data > data)//如果当前结点数>要插入的数,向当前结点的左子树去找插入位置
            {
                pCur = pCur->_pLeft;
            }
            else//如果当前结点数<要插入的数,向当前结点的右子树去找插入位置
            {
                pCur = pCur->_pRight;
            }
        }
        //插入新结点
        if (data > pParent->_data)//如果插入的元素比它要插入位置的元素大,则要插入的元素应该是要插入位置结点的右孩子
        {
            pParent->_pRight = BuyBSTNode(data);
            return true;
        }
        if (data < pParent->_data)//如果插入的元素比它要插入位置的元素小,则要插入的元素应该是要插入位置结点的左孩子
        {
            pParent->_pLeft = BuyBSTNode(data);
            return true;
        }
    }
    return false;
}

bool DelectBSTree(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    BSTNode* pCur = NULL;
    BSTNode* pParent = NULL;
    if (NULL == *pRoot)
        return false;
    else
    {
        //找到待删除结点

        pCur = *pRoot;
        while (pCur)
        {
            if (data > pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else if (data < pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else
                break;
        }
        //删除结点

        //待删结点是叶子节点或者只有右孩子
        if (NULL == pCur->_pLeft)
        {
            if (pCur == *pRoot)//若果删除的是根结点
                *pRoot = pCur->_pRight;
            else if (pCur == pParent->_pLeft)
                pParent->_pLeft = pCur->_pRight;
            else
                pParent->_pRight = pCur->_pRight;
        }
        //只有左孩子
        else if (NULL == pCur->_pRight)
        {
            if (pCur == *pRoot)//若果删除的是根结点
                *pRoot = pCur->_pLeft;
            else if (pCur == pParent->_pLeft)
                pParent->_pLeft = pCur->_pLeft;
            else
                pParent->_pRight = pCur->_pLeft;
        }
        //左右孩子都存在
        else
        {
            //替代法,向待删除点的右子树找最左边的数(最小)/向待删除点的左子树找最右边的数(最大),将待删除点与最左边/最右边的数交换,删除最左边/最右边的数
            BSTNode* Inorder = pCur->_pRight;

            while (Inorder->_pLeft)//除了循环函数,Inorder不可能有左孩子
            {
                pParent = Inorder;
                Inorder = Inorder->_pLeft;
            }
            pCur->_data = Inorder->_data;//交换
            if (Inorder == pParent->_pLeft)
                pParent->_pLeft = Inorder->_pRight;
            else if (Inorder == pParent->_pRight)
                pParent->_pRight = Inorder->_pRight;
            pCur = Inorder;
        }
    }
    free(pCur);
    pCur = NULL;
    return true;
}

BSTNode* FindBSTree(BSTNode* pRoot, BSDataType data)
{
    BSTNode* pCur = NULL;
    if (NULL == pRoot)
        return NULL;

    pCur = pRoot;
    while (pCur)
    {
        if (pCur->_data == data)
        {
            return pCur;
        }
        else if (pCur->_data > data)
        {
            pCur = pCur->_pLeft;
        }
        else
        {
            pCur = pCur->_pRight;
        }
    }
    return NULL;
}

void DestroyBSTree(BSTNode** pRoot)
{
    assert(pRoot);
    if (*pRoot)
    {
        DestroyBSTree(&(*pRoot)->_pLeft);
        DestroyBSTree(&(*pRoot)->_pRight);
        free(*pRoot);
        *pRoot = NULL;
    }
}

BSTNode* FindBSTreeNor(BSTNode* pRoot, BSDataType data)
{
    if (NULL == pRoot)
        return NULL;
    else if (data == pRoot->_data)
        return pRoot;
    else if (data < pRoot->_data)
        return FindBSTreeNor(pRoot->_pLeft, data);
    else
        return FindBSTreeNor(pRoot->_pRight, data);

}

bool InsertBSTreeNor(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);
    if (NULL == *pRoot)
        *pRoot = BuyBSTNode(data);
    else
    {
        if (data == (*pRoot)->_data)
        {
            return false;
        }
        else if (data < (*pRoot)->_data)
            return InsertBSTree(&(*pRoot)->_pLeft, data);
        else
            return InsertBSTree(&(*pRoot)->_pRight, data);

    }
    return true;
}

bool DelectBSTreeNor(BSTNode** pRoot, BSDataType data)
{
    assert(pRoot);

    if (NULL == *pRoot)
        return false;
    else
    {

        if (data > (*pRoot)->_data)
        {
            return DelectBSTreeNor(&(*pRoot)->_pRight, data);
        }
        else if (data < (*pRoot)->_data)
        {
            return DelectBSTreeNor(&(*pRoot)->_pLeft, data);
        }
        else //data == (*pRoot)->_data
        {
            //这时已经找到了待删除结点
            BSTNode* pDel = *pRoot;
            if (NULL == pDel->_pLeft)
            {
                *pRoot = pDel->_pRight;
                free(pDel);
                return true;
            }
            else if (NULL == (*pRoot)->_pRight)
            {
                *pRoot = pDel->_pLeft;
                free(pDel);
                return true;
            }
            else //左右孩子都存在
            {
                BSTNode* Inorder = pDel->_pRight;
                while (Inorder->_pLeft)
                    Inorder = Inorder->_pLeft;
                pDel->_data = Inorder->_data;
                return DelectBSTreeNor(&(*pRoot)->_pRight, pDel->_data);
            }
        }
    }
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"BSTree.h"

int main()
{
    BSTNode* pRoot;
    InitBSTree(&pRoot);
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        InsertBSTreeNor(&pRoot, i);
    }
    //DestroyBSTree(&pRoot);
    InOrder(pRoot);
    BSTNode* ret = FindBSTreeNor(pRoot, 4);
    printf("\n");
    DelectBSTreeNor(&pRoot, 3);
    InOrder(pRoot);
    printf("\n");
    if (ret)
    {
        printf("该元素在二叉树中\n");
    }
    else
    {
        printf("该元素不在二叉树中\n");
    }

    return 0;
}
    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/huaijiu123/article/details/82465620
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞