二叉搜索树的查找、插入、删除的递归与非递归实现(C语言)

【概念】
什么是二叉搜索树?
二叉搜索树又称二叉排序树(按照中序遍历,可以得到一组有序的序列),它或者是一颗空树,或者是具有以下性质的二叉树:
若他的左子树不为空,则左子树上所有节点的值都小于根结点的值。
若他的右子树不为空,则右子树上所有节点的值都大于根结点的值。
他的左右子树也分别为二叉搜索树。

【二叉搜索树的简单操作】

查找

根据二叉搜索树的性质可知,在一棵树中,根节点比其左子树任何一个值都大,比右子树任何一个值都小,所以可将查找分为三步(前提:根节点不为空):

  • 用待查找的值=根节点的值,则直接返回true;
  • 如果待查找的值>根节点的值,则在其右子树中查找;
  • 如果待查找的值<根节点的值,在其左子树中查找。

话不多说,直接上代码(首先是非递归)

int BSTreeNodeFindNor(BSTreeNode pRoot,DataType data)//查找(非递归)
{
    if (NULL == pRoot)
    {
        printf("树为空\n");
    }
    while (pRoot)
    {
        if (pRoot->_data == data)
        {
            return 1;
        }
        else if (pRoot->_data > data)
        {
            pRoot = pRoot->_pLeft;
        }
        else if (pRoot->_data < data)
        {
            pRoot = pRoot->_pRight;
        }
        else
        {
            return 0;
        }
    }
    return 0;
}

递归

int BSTreeNodeFind(BSTreeNode pRoot, DataType data)//查找(递归)
{
    if (NULL == pRoot)
    {
        return 0;
    }
    else
    {
        if (data == pRoot->_data)
            return 1;
        else if (data < pRoot->_data)
            return BSTreeNodeFind(pRoot->_pLeft, data);
        else if (data > pRoot->_data)
            return BSTreeNodeFind(pRoot->_pRight, data);
    }
    return 0;
}

插入

在二叉搜索树中插入新元素时,必须确保该元素不在二叉树中,如果在则不进行插入,否则将新元素插入到搜索停止的地方。具体步骤分为两步:

  • 树为空,则直接插入,然后返回;
  • 树不为空,按二叉搜索树的性质查找插入的位置,若带插入的元素小于她的双亲,则插入到双亲左侧,否则插入到双亲右侧。

具体代码框架如图所示:
《二叉搜索树的查找、插入、删除的递归与非递归实现(C语言)》

非递归代码如下:

void BSTreeNodeInsertNor(BSTreeNode* pRoot, DataType data)//插入(非递归)
{
    //树为空,直接插入
    if (NULL == *pRoot)
    {
        *pRoot = BuyBSTreeNode(data);
        return;
    }
    //树不为空
    //找插入位置
    else
    {
        BSTreeNode pCur = NULL;
        BSTreeNode pParent = NULL;
        assert(pRoot);
        pCur = *pRoot;
        while (pCur)
        {
            if (data == pCur->_data)
            {
                return;
            }
            else if (data < pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (data > pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else
            {
                return;
            }
        }
        if (pParent->_data<data)
            pParent->_pRight = BuyBSTreeNode(data);
        else if (pParent->_data>data)
            pParent->_pLeft = BuyBSTreeNode(data);
    }
}

递归代码如下:

int BSTreeNodeInsert(BSTreeNode* pRoot, DataType data)//插入(递归)
{
    if (NULL == *pRoot)
    {
        *pRoot = BuyBSTreeNode(data);
        return 1;
    }
    else
    {
        if (data < (*pRoot)->_data)
            BSTreeNodeInsert(&(*pRoot)->_pLeft, data);
        else if (data>(*pRoot)->_data)
            BSTreeNodeInsert(&(*pRoot)->_pRight, data);
        else
            return 0;
    }
}

删除

首先查找元素是否在二叉树中,如果不存在,则返回,否则要删除的节点可能分下面四种情况:

  1. 要删除的节点无孩子节点
  2. 要删除的节点只有左孩子节点
  3. 要删除的节点只有右孩子节点
  4. 要删除的节点左右孩子都存在

四种情况的具体分析过程如图所示:
《二叉搜索树的查找、插入、删除的递归与非递归实现(C语言)》

非递归代码如下:

void DeleteBSTreeNodeNor(BSTreeNode* pRoot, DataType data)//删除(非递归)
{
    assert(pRoot);
    //查找值为data的节点
    BSTreeNode pCur = NULL;//要删除的的节点
    BSTreeNode pParent = NULL;
    pCur = *pRoot;
    while (pCur)
    {
        if (data == pCur->_data)
        {
            //pParent = pCur;
            break;
        }
        else if (data < pCur->_data)
        {
            pParent = pCur;
            pCur = pCur->_pLeft;
        }
        else
        {
            pParent = pCur;
            pCur = pCur->_pRight;
        }
    }
    //没找到,直接返回
    if (NULL == pCur)
    {
        printf("待删除节点不在二叉树中\n");
        return;
    }
    //找到了,分情况讨论
    //1.要删除的节点没有左孩子,即只有右孩子或左右孩子都没有
    if (pCur->_pLeft == NULL)
    {
        if (pCur == *pRoot)
            *pRoot = pCur->_pRight;
        else
        {
            if (pCur == pParent->_pLeft)
            {
                pParent->_pLeft = pCur->_pRight;
            }
            else
            {
                pParent->_pRight = pCur->_pRight;
            }
        }
    }
    //2.要删除的节点没有右孩子,即只有左孩子或左右孩子都没有
    else if (pCur->_pRight == NULL)
    {
        if (pCur == *pRoot)
        {
            *pRoot = pCur->_pLeft;
        }
        else
        {
            if (pCur == pParent->_pLeft)
            {
                pParent->_pLeft = pCur->_pLeft;
            }
            else
            {
                pParent->_pRight = pCur->_pLeft;
            }
        }
    }
    //3.要删除的节点左右孩子都存在,在其右子树中找一个最小的节点,替代待删除节点
    else
    {
        BSTreeNode pDel = pCur->_pRight;
        pParent = pCur;
        while (pDel->_pLeft)
        {
            pParent = pDel;
            pDel = pDel->_pLeft;
        }
        pCur->_data = pDel->_data;
        if (pDel == pParent->_pLeft)
        {
            pParent->_pLeft = pDel->_pRight;
        }
        else
        {
            pParent->_pRight = pDel->_pRight;
        }
        pCur = pDel;
        free(pDel);
    }
}

递归代码如下:

int DeleteBSTreeNode(BSTreeNode* pRoot, DataType data)//删除(递归)
{
    if (NULL == *pRoot)
    {
        return 0;
    }
    if (data == (*pRoot)->_data)
        return 1;
    else if (data > (*pRoot)->_data)
        return DeleteBSTreeNode(&(*pRoot)->_pRight, data);
    else if (data < (*pRoot)->_data)
        return DeleteBSTreeNode(&(*pRoot)->_pLeft, data);
    else
    {
        BSTreeNode pDel = *pRoot;
        if (NULL == pDel->_pLeft)
            (*pRoot) = pDel->_pRight;
        else if (NULL == pDel->_pRight)
            (*pRoot) = pDel->_pLeft;
        else
        {
            //左右子树都存在
            BSTreeNode pDel = (*pRoot)->_pRight;
            while (pDel->_pLeft)
            {
                pDel = pDel->_pLeft;
            }
            (*pRoot)->_data = pDel->_data;
            return DeleteBSTreeNode(&(*pRoot)->_pRight, pDel->_data);
        }
    }
}

完整代码

#pragma once
#include<assert.h>
#include<malloc.h>
#include<stdio.h>
typedef int DataType;

typedef struct BSTreeNode
{
    struct BSTreeNode* _pLeft;
    struct BSTreeNode* _pRight;
    DataType _data;
}BSTNode,*BSTreeNode;

void BSTreeNodeInit(BSTreeNode* pRoot)
{
    *pRoot = NULL;
}

BSTreeNode BuyBSTreeNode(DataType data)
{
    BSTreeNode pNewNode = (BSTreeNode)malloc(sizeof(BSTNode));//malloc函数开辟的空间一定要判空
    if (NULL == pNewNode)
    {
        assert(0);
        return NULL;
    }
    pNewNode->_data = data;
    pNewNode->_pLeft = NULL;
    pNewNode->_pRight = NULL;
    return pNewNode;
}

void BSTreeNodeInsertNor(BSTreeNode* pRoot, DataType data)//插入(非递归)
{
    //树为空,直接插入
    if (NULL == *pRoot)
    {
        *pRoot = BuyBSTreeNode(data);
        return;
    }
    //树不为空
    //找插入位置
    else
    {
        BSTreeNode pCur = NULL;
        BSTreeNode pParent = NULL;
        assert(pRoot);
        pCur = *pRoot;
        while (pCur)
        {
            if (data == pCur->_data)
            {
                return;
            }
            else if (data < pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (data > pCur->_data)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else
            {
                return;
            }
        }
        if (pParent->_data<data)
            pParent->_pRight = BuyBSTreeNode(data);
        else if (pParent->_data>data)
            pParent->_pLeft = BuyBSTreeNode(data);
    }
}

int BSTreeNodeInsert(BSTreeNode* pRoot, DataType data)//插入(递归)
{
    if (NULL == *pRoot)
    {
        *pRoot = BuyBSTreeNode(data);
        return 1;
    }
    else
    {
        if (data < (*pRoot)->_data)
            BSTreeNodeInsert(&(*pRoot)->_pLeft, data);
        else if (data>(*pRoot)->_data)
            BSTreeNodeInsert(&(*pRoot)->_pRight, data);
        else
            return 0;
    }
}

int BSTreeNodeFindNor(BSTreeNode pRoot,DataType data)//查找(非递归)
{
    if (NULL == pRoot)
    {
        printf("树为空\n");
    }
    while (pRoot)
    {
        if (pRoot->_data == data)
        {
            return 1;
        }
        else if (pRoot->_data > data)
        {
            pRoot = pRoot->_pLeft;
        }
        else if (pRoot->_data < data)
        {
            pRoot = pRoot->_pRight;
        }
        else
        {
            return 0;
        }
    }
    return 0;
}

int BSTreeNodeFind(BSTreeNode pRoot, DataType data)//查找(递归)
{
    if (NULL == pRoot)
    {
        return 0;
    }
    else
    {
        if (data == pRoot->_data)
            return 1;
        else if (data < pRoot->_data)
            return BSTreeNodeFind(pRoot->_pLeft, data);
        else if (data > pRoot->_data)
            return BSTreeNodeFind(pRoot->_pRight, data);
    }
    return 0;
}

void DeleteBSTreeNodeNor(BSTreeNode* pRoot, DataType data)//删除(非递归)
{
    assert(pRoot);
    //查找值为data的节点
    BSTreeNode pCur = NULL;//要删除的的节点
    BSTreeNode pParent = NULL;
    pCur = *pRoot;
    while (pCur)
    {
        if (data == pCur->_data)
        {
            //pParent = pCur;
            break;
        }
        else if (data < pCur->_data)
        {
            pParent = pCur;
            pCur = pCur->_pLeft;
        }
        else
        {
            pParent = pCur;
            pCur = pCur->_pRight;
        }
    }
    //没找到,直接返回
    if (NULL == pCur)
    {
        printf("待删除节点不在二叉树中\n");
        return;
    }
    //找到了,分情况讨论
    //1.要删除的节点没有左孩子,即只有右孩子或左右孩子都没有
    if (pCur->_pLeft == NULL)
    {
        if (pCur == *pRoot)
            *pRoot = pCur->_pRight;
        else
        {
            if (pCur == pParent->_pLeft)
            {
                pParent->_pLeft = pCur->_pRight;
            }
            else
            {
                pParent->_pRight = pCur->_pRight;
            }
        }
    }
    //2.要删除的节点没有右孩子,即只有左孩子或左右孩子都没有
    else if (pCur->_pRight == NULL)
    {
        if (pCur == *pRoot)
        {
            *pRoot = pCur->_pLeft;
        }
        else
        {
            if (pCur == pParent->_pLeft)
            {
                pParent->_pLeft = pCur->_pLeft;
            }
            else
            {
                pParent->_pRight = pCur->_pLeft;
            }
        }
    }
    //3.要删除的节点左右孩子都存在,在其右子树中找一个最小的节点,替代待删除节点
    else
    {
        BSTreeNode pDel = pCur->_pRight;
        pParent = pCur;
        while (pDel->_pLeft)
        {
            pParent = pDel;
            pDel = pDel->_pLeft;
        }
        pCur->_data = pDel->_data;
        if (pDel == pParent->_pLeft)
        {
            pParent->_pLeft = pDel->_pRight;
        }
        else
        {
            pParent->_pRight = pDel->_pRight;
        }
        pCur = pDel;
        free(pDel);
    }
}

int DeleteBSTreeNode(BSTreeNode* pRoot, DataType data)//删除(递归)
{
    if (NULL == *pRoot)
    {
        return 0;
    }
    if (data == (*pRoot)->_data)
        return 1;
    else if (data > (*pRoot)->_data)
        return DeleteBSTreeNode(&(*pRoot)->_pRight, data);
    else if (data < (*pRoot)->_data)
        return DeleteBSTreeNode(&(*pRoot)->_pLeft, data);
    else
    {
        BSTreeNode pDel = *pRoot;
        if (NULL == pDel->_pLeft)
            (*pRoot) = pDel->_pRight;
        else if (NULL == pDel->_pRight)
            (*pRoot) = pDel->_pLeft;
        else
        {
            //左右子树都存在
            BSTreeNode pDel = (*pRoot)->_pRight;
            while (pDel->_pLeft)
            {
                pDel = pDel->_pLeft;
            }
            (*pRoot)->_data = pDel->_data;
            return DeleteBSTreeNode(&(*pRoot)->_pRight, pDel->_data);
        }
    }
}

void CreatBSTree(BSTreeNode* pRoot, DataType a[], int size) { int i = 0; for (; i < size; ++i) { BSTreeNodeInsert(&(*pRoot), a[i]); } } void InpRoot(BSTreeNode pRoot)//中序遍历(递归) { if (pRoot) { InpRoot(pRoot->_pLeft); printf("%d ", pRoot->_data); InpRoot(pRoot->_pRight); } } void TestBSTreeNode() { BSTreeNode pRoot=NULL; BSTreeNodeInit(&pRoot); int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 }; CreatBSTree(&pRoot, a, sizeof(a) / sizeof(a[0])); InpRoot(pRoot); printf("\n"); if (!BSTreeNodeFindNor(pRoot, 4)) printf("Not Found\n"); else printf("Found\n"); printf("\n"); if (!BSTreeNodeFind(pRoot, 4)) printf("Not Found\n"); else printf("Found\n"); DeleteBSTreeNodeNor(&pRoot, 10); InpRoot(pRoot); printf("\n"); DeleteBSTreeNode(&pRoot, 10); InpRoot(pRoot); printf("\n"); }
    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/WWT_LB1314/article/details/80274927
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞