热门标签 | 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模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • 本文探讨了如何优化和正确配置Kafka Streams应用程序以确保准确的状态存储查询。通过调整配置参数和代码逻辑,可以有效解决数据不一致的问题。 ... [详细]
  • 本文介绍如何在QT框架中使用QWebSocket和QTcpSocket实现SSL加密通信,涵盖单向认证设置。单向认证常见于Web通信场景,其中客户端验证服务端证书,而服务端不验证客户端证书。 ... [详细]
  • 基因组浏览器中的Wig格式解析
    本文详细介绍了Wiggle(Wig)格式及其在基因组浏览器中的应用,涵盖variableStep和fixedStep两种主要格式的特点、适用场景及具体使用方法。同时,还提供了关于数据值和自定义参数的补充信息。 ... [详细]
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社区 版权所有