IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 二叉查找树查找,插入,删除算法详解(C语言实现,注释最全,单步调试通过) -> 正文阅读

[C++知识库]二叉查找树查找,插入,删除算法详解(C语言实现,注释最全,单步调试通过)

二叉查找树查找,插入,删除算法详解(C语言实现,注释最全,单步调试通过)

二叉查找树的定义

二叉排序树 (Binary Sort Tree) 又称二叉查找树,它是一种对排序和查找都很有用的特殊二叉树。

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1) 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2) 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3) 它的左、 右子树也分别为二叉排序树。

二叉排序树是递归定义的。 由定义可以得出二叉排序树的一个重要性质:中序遍历一棵二叉
树时可以得到一个结点值递增的有序序列。

二叉查找树的实现

#include <stdio.h>
#include <stdlib.h>
#define true 1
#define false 0
#define ElemType int
#define KeyType int

/**
 * 二叉排序树的结点结构定义
 */ 
typedef struct _BinaryNode
{
    /* data */
    ElemType data;
    struct _BinaryNode *lchild;
    struct _BinaryNode *rchild;
}BinaryNode,*BinaryTree;

/**
 * @brief 二叉查找树查找算法
 *
 * @param[in] Node 当前查找的二叉查找树的结点
 * @param[in] KeyData 待查找的数据
 * @param[in] FatherNode 当前查找的二叉查找树的结点的父结点
 * @param[out] FoundNode 如果找到,存放找到的结点;如果没找到,值为空。
 * @param[out] FatherOfFoundNode 如果找到,存放找到的结点的父结点;如果没找到,存放最后查找的那个结点。
 * 
 * @return int
 * @retval 1 查找成功
 * @retval 0 查找失败
 */
int SearchBST(BinaryTree Node,KeyType KeyData,BinaryTree FatherNode,BinaryTree *FoundNode,BinaryTree *FatherOfFoundNode)
{
    /**
     * 此函数是递归的,如果Node结点为空,说明查无可查,查找失败。
     * 给函数的输出参数FatherOfFoundNode指向最后一个查找的结点。
     */ 
    if(!Node)
    {
        *FatherOfFoundNode = FatherNode;
        *FoundNode = NULL;

        return false;
    }
    /**
     * 此函数是递归的,如果Node结点的数据与查找的数据相同,说明已查到。
     * 给函数的输出参数FoundNode指向查找到的结点,函数的输出参数FatherOfFoundNode指向查找结点的父结点。
     */ 
    if(KeyData == Node->data)
    {
        *FoundNode = Node;
        *FatherOfFoundNode = FatherNode;
        return true;
    }
    /**
     * 此函数是递归的,如果Node结点的数据比查找的数据大,说明待查找数据可能在Node结点的左子树中。查找左子树。
     */ 
    else if(KeyData < Node->data)
    {
        return SearchBST(Node->lchild, KeyData, Node, FoundNode,FatherOfFoundNode);
    }
    /**
     * 此函数是递归的,如果Node结点的数据比查找的数据小,说明待查找数据可能在Node结点的右子树中。查找右子树。
     */ 
    else
    {
        return SearchBST(Node->rchild, KeyData, Node, FoundNode,FatherOfFoundNode);
    }

}
/**
 * @brief 二叉查找树查找最小值算法
 *
 * @param[in] BinaryNode 当前查找的二叉查找树的结点
 * 
 * @return BinaryTree 
 * @retval !NULL 查找到的结点指针
 * @retval NULL 查找失败
 */
BinaryTree FindBSTMin(BinaryTree BinaryNode)
{
    if(BinaryNode == NULL)
    {
        return NULL;
    }
    else
    {
        if(BinaryNode->lchild == NULL)
        {
            return BinaryNode;
        }
        else
        {
            return FindBSTMin(BinaryNode->lchild);
        }
    }

}
/**
 * @brief 二叉查找树查找最大值算法
 *
 * @param[in] BinaryNode 当前查找的二叉查找树的结点
 * 
 * @return BinaryTree 
 * @retval !NULL 查找到的结点指针
 * @retval NULL 查找失败
 */
BinaryTree FindBSTMax(BinaryTree BinaryNode)
{
    if(BinaryNode == NULL)
    {
        return NULL;
    }
    else
    {
        if(BinaryNode->rchild == NULL)
        {
            return BinaryNode;
        }
        else
        {
            return FindBSTMax(BinaryNode->rchild);
        }
    }

}

/**
 * @brief 二叉查找树查找算法
 *
 * @param[in] Tree 指向待查找的二叉查找树的结点
 * @param[in] Data 待查找的数据
 * 
 * @return int
 * @retval 1 插入成功
 * @retval 0 插入失败
 */
int InsertBST(BinaryTree *Tree,ElemType Data)
{
    BinaryTree FoundNode = NULL;
    BinaryTree FatherOfFoundNode = NULL;
    /**
     * 插入之前先查找,查找失败就做插入操作
     */ 
    if(!SearchBST(*Tree,Data,NULL,&FoundNode,&FatherOfFoundNode))
    {
        /**
         * 初始化插入结点
         */ 
        BinaryTree InsertNode = (BinaryTree)malloc(sizeof(BinaryNode));
        InsertNode->data = Data;
        InsertNode->lchild = NULL;
        InsertNode->rchild = NULL;
        /**
         * 最后一次查找的结点为空,说明整个二叉排序树是空树,此时插入的结点是根结点
         */ 
        if(!FatherOfFoundNode)
        {
            *Tree = InsertNode;
        }
        else if(Data < FatherOfFoundNode->data)
        {
            FatherOfFoundNode->lchild = InsertNode;
        }
        else
        {
            FatherOfFoundNode->rchild = InsertNode;
        }
        return true;
    }
    /**
     * 插入之前先查找,查找成功返回失败
     */ 
    else
    {
        return false;
    }
}
/**
 * @brief 二叉查找树删除算法
 *
 * @param[in] DeleteNode 指向待查找的二叉查找树的结点的指针
 * @param[in] FatherOfDeleteNode 指向待查找的二叉查找树结点的父结点的指针
 * 
 * @return int
 * @retval 1 插入成功
 * @retval 0 插入失败
 */
int DeleteNode(BinaryTree *DeleteNode,BinaryTree *FatherOfDeleteNode)
{
    BinaryTree FatherOfPrecursorForDeleteNode = NULL;//待删除结点的前驱结点的父亲
    BinaryTree PrecursorForDeleteNode = NULL;//待删除结点的前驱结点
    /**
     * 情况1:待删除结点DeleteNode本身就是叶子结点
     */ 
    if (!(*DeleteNode)->lchild && !(*DeleteNode)->rchild) {
        /**
         * 情况1.1:待删除结点DeleteNode本身就是叶子结点,且是为他父亲的左孩子,将父结点的左孩子结点指向空
         */ 
        if((*FatherOfDeleteNode)->lchild == *DeleteNode)
        {
            (*FatherOfDeleteNode)->lchild = NULL;
        }
        /**
         * 情况1.2:待删除结点DeleteNode本身就是叶子结点,且是为他父亲的右孩子,将父结点的右孩子结点指向空
         */ 
        else
        {
            (*FatherOfDeleteNode)->rchild = NULL;
        }
        /**
         * 释放待删除结点的内存
         */ 
        free(*DeleteNode);
        *DeleteNode = NULL;
    }
    /**
     * 情况2:右子树为空,左子树不为空,只需用待删除结点DeleteNode的父结点指向待删除结点DeleteNode的左子树即可;
     * 注意区分待删除结点是他父结点的左孩子还是右孩子
     */ 
    else if(!(*DeleteNode)->rchild)
    {
        if((*FatherOfDeleteNode)->lchild == *DeleteNode)
        {
            (*FatherOfDeleteNode)->lchild = (*DeleteNode)->lchild;
        }
        else
        {
            (*FatherOfDeleteNode)->rchild = (*DeleteNode)->lchild;
        }
        free(*DeleteNode);
        *DeleteNode = NULL;
        
    }
    /**
     * 情况3:左子树为空,右子树不为空,只需用待删除结点DeleteNode的父结点指向待删除结点DeleteNode的右子树即可;
     * 注意区分待删除结点是他父结点的左孩子还是右孩子
     */ 
    else if(!(*DeleteNode)->lchild)
    {
        if((*FatherOfDeleteNode)->rchild == *DeleteNode)
        {
            (*FatherOfDeleteNode)->rchild = (*DeleteNode)->rchild;
        }
        else
        {
            (*FatherOfDeleteNode)->lchild = (*DeleteNode)->rchild;
        }
        free(*DeleteNode);
        *DeleteNode = NULL;
        
    }
    else
    {
        /**
         * 情况4:左右子树均不为空,用待删除结点的前驱结点的data替换待删除结点的data,删除待删除结点的前驱结点
         */ 
        FatherOfPrecursorForDeleteNode = *DeleteNode;//待删除结点的前驱结点的父亲初始化为待删除结点,即默认待删除结点的前驱结点为其左子树
        PrecursorForDeleteNode = (*DeleteNode)->lchild;//待删除结点的前驱结点初始化,默认待删除结点的前驱结点为待删除结点的左子树
        //遍历,找到结点 DeleteNode 的直接前驱
        while (PrecursorForDeleteNode->rchild)
        {
            FatherOfPrecursorForDeleteNode = PrecursorForDeleteNode;
            PrecursorForDeleteNode = PrecursorForDeleteNode->rchild;
        }
        //循环之后PrecursorForDeleteNode即为待删除结点的前驱结点,FatherOfPrecursorForDeleteNode即为待删除结点的前驱结点的父亲
        
        //直接改变结点 DeleteNode 的值
        (*DeleteNode)->data = PrecursorForDeleteNode->data;
        //此种情况是待删除结点 DeleteNode 的左子树没有右子树,这时待删除结点的前驱结点为其左子树,待删除结点的前驱结点的父亲为待删除结点本身。
        if (FatherOfPrecursorForDeleteNode == *DeleteNode) {
            //直接将待删除结点的前驱结点的左子树上移即可
            (*DeleteNode)->lchild = PrecursorForDeleteNode->lchild;

        }
        else {
            //此时待删除结点的前驱结点不是他的左孩子,那么找到的待删除结点的前驱结点有如下特征:只存在有左孩子无右孩子或左右孩子均无的这两种情况。
            //改待删除结点的前驱结点的父亲FatherOfPrecursorForDeleteNode 指向待删除结点的前驱结点PrecursorForDeleteNode的左孩子结点
            //此种情况已经考虑待删除结点的前驱结点没有左孩子。
            FatherOfPrecursorForDeleteNode->rchild = PrecursorForDeleteNode->lchild;

        }
        //删除直接前驱结点
        free(PrecursorForDeleteNode);
        PrecursorForDeleteNode = NULL;
    }
    return true;
}

/**
 * @brief 二叉查找树删除整颗树算法
 *
 * @param[in] BinaryNode 待删除的二叉查找树的根结点
 * 
 * @return BinaryTree
 * @retval NULL 删除成功
 */
BinaryTree DeleteBST(BinaryTree BinaryNode)
{
    if(BinaryNode != NULL)
    {
        DeleteBST(BinaryNode->lchild);
        DeleteBST(BinaryNode->rchild);
        free(BinaryNode);
    }
    return NULL;
}

//测试案例
int main(void)
{
    int i;
    //int Squence[5] = {3, 4, 2, 5, 9};
    int Squence2[] = {8, 4, 10, 2, 6, 12, 5};
    BinaryTree Tree = NULL;
    for (i = 0; i < sizeof(Squence2)/sizeof(Squence2[0]);++i)
    {
        int ReturnCode = InsertBST(&Tree, Squence2[i]);
        printf("insert %d result %d\r\n", Squence2[i], ReturnCode);
    }
    BinaryTree FoundNode = NULL;
    BinaryTree FatherOfFoundNode = NULL;
    
    if(SearchBST(Tree,8,NULL,&FoundNode,&FatherOfFoundNode))
    {
        DeleteNode(&FoundNode,&FatherOfFoundNode);
    }

}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 22:56:03  更:2021-07-22 22:56:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/1 21:19:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码