热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

二叉排序树的删除算法解析

二叉排序树删除操作的几种情况要删除的结点在二叉排序树中是叶子结点:则可以直接删除,因为删除它们对于整棵树来说,其他节点的结构并不受到影响要删除的结点只有左子树或者右子树:删除结点后

二叉排序树删除操作的几种情况



  1. 要删除的结点在二叉排序树中是叶子结点:

    则可以直接删除,因为删除它们对于整棵树来说,其他节点的结构并不受到影响



  2. 要删除的结点只有左子树或者右子树:

    删除结点后,将它的左子树或右子树移动到删除结点的位置即可(子承父业)



  3. 要删除的结点既有左子树又有右子树:

    简单的想法:让删除结点的左子树成为删除结点的双亲的左子树,然后将删除结点的右子树所有结点进行重新插入

    更好的算法:在删除的结点的左右子树中寻找有一个结点来代替删除结点(与其最接近的两个数之一),然后再删除这个用来替换的结点(这个用来替换的结点 一定是一个叶子结点或者只有一个左孩子)






二叉排序树删除算法源码

//若二叉排序树中存在关键字等于key的数据元素,则删除该数据元素并返回TURE;否则返回FALSE
//算法中采用了递归的实现方式
status DeleteBST(BiTree* T, int key){
if(!*T) //不存在关键字等于key的数据元素
return false;
else{
if (key == (*T)->data) //找到关键字等于key的数据元素
return Delete(T);
else if (key<(*T)->data)
//这里T是二叉树的指针,*T得到根节点对象,&表示以引用传递参数(可以对原对象进行修改)(引用修饰整体)
return DeleteBST(&(*T)->lchild,key);
else
return DeleteBST(&(*T)->rchild,key);
}
}

可以看出,其实二叉排序树的删除算法的实现方式和二叉排序树的查找算法几乎完全相同,唯一的不同就是使用了Delete函数,对当前结点进行删除操作。




Delete函数的具体实现

//二叉排序树中删除结点p,并重新连接它的左子树或右子树
status Delete(BiTree* p){
BiTree q, s;
//右子树为空则只需要连接它的左子树
if ((*p)->rchild==NULL){ //*p得到根节点
//free根节点,保留左子树
q = *p; *p = (*p)->lchild; free(q);
}
else if ((*p)->lchild==NULL){ //只需要连接它的右子树
q = *p; *p = (*p)->rchild; free(q);
}
//左右子树均非空
else{
q = *p; s = (*p)->lchild;
while (s->rchild){
//转左,然后向右到尽头(找到待删除结点的直接前驱)(也可以选择找它的直接后继)
q = s; s = s->rchild;
}
//上面while循环的结果为:s为直接前驱,q为s的双亲
(*p)->data = s->data;
//以下就是在删除s结点(这两种情况会在下文进行举例说明)
if (q != *p)
q->rchild = s->lchild;
//如果第一个s就没有右孩子的话,就会有(q = *p),进而出现这种情况
else
q->lchild = s->lchild;
free(s);
}
return true;
}



Delete函数中 q!=*p 的情况




  • 如上图所示,将p指向的结点用s指向的结点覆盖



  • 之后,按照上文中代码的逻辑,将s结点的左孩子赋值给q结点的右孩子



  • 操作的结果如下图所示:







Delete函数中 q=*p 的情况




  • 如上图所示,将p指向的结点用s指向的结点覆盖



  • 之后,按照上文中代码的逻辑,将s结点的左孩子赋值给q结点的左孩子



  • 操作的结果如下图所示:






推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 使用Numpy实现无外部库依赖的双线性插值图像缩放
    本文介绍如何仅使用Numpy库,通过双线性插值方法实现图像的高效缩放,避免了对OpenCV等图像处理库的依赖。文中详细解释了算法原理,并提供了完整的代码示例。 ... [详细]
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文探讨了如何在发布 XenApp 应用时,通过命令行参数实现启动时的参数传递。特别介绍了静态和动态参数传递的方法,并详细解释了 ICA 文件中两种参数传递方式的区别及安全检查机制。 ... [详细]
  • 本文介绍如何通过注册表编辑器自定义和优化Windows文件右键菜单,包括删除不需要的菜单项、添加绿色版或非安装版软件以及将特定应用程序(如Sublime Text)添加到右键菜单中。 ... [详细]
  • MQTT技术周报:硬件连接与协议解析
    本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
author-avatar
半夏✔
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有