入门数据结构JAVADS——如何构建一棵简单二叉排序树

目录

前言

什么是二叉排序树

二叉排序树的特点

二叉排序树示意图

构建二叉排序树

 插入元素

 搜索元素

 删除元素

完整代码

结尾

前言

在整个十一月,笔者因为一些原因停笔了,但马上迈入12月进而进入2025年,笔者决定不再偷懒了,继续更新以促进学习的积极性.闲话说到这,今天更新的是如何构建一个简单的二叉排序树

什么是二叉排序树

二叉排序树(Binary Search Tree,简称 BST)是一种特殊的二叉树,它的每个节点都满足以下性质:

  1. 左子树上所有节点的值,都小于根节点的值。
  2. 右子树上所有节点的值,都大于根节点的值。
  3. 左子树和右子树本身也都是二叉排序树(递归定义)。

二叉排序树的特点

  • 值的唯一性:二叉排序树中每个节点的值必须是唯一的(不允许重复值)。
  • 有序性:中序遍历(左-根-右)二叉排序树时,会得到一个递增的有序序列
  • 动态性:支持动态插入和删除元素,能够随时维护有序性。
  • 时间复杂度:平均情况下插入、查找、删除的时间复杂度为 O(log⁡n),但在极端情况下(树退化为链表),复杂度可能退化到 O(n)。

举个例子

二叉排序树示意图

假设我们依次插入以下数字:50, 30, 70, 20, 40, 60, 80
构造的二叉排序树如下:

        50/    \30      70/  \    /  \20   40  60   80

此时,中序遍历二叉树,即可得到顺序排列. 

构建二叉排序树

想要写一棵简单的二叉排序树,大致需要三个方法,分别是 插入结点,查找结点,删除结点

我们首先创建好结点类

   static  class TreeNode{public  int val;public  TreeNode left;public  TreeNode right;public TreeNode(int val)   {this.val = val;}}public  TreeNode root;

 插入元素

插入元素是比较简单的,思路如下:

1.   首先判断树是不是空的,如果是空的,插入元素即为根

2.   如果不是空的,那么就借助双亲结点,去找需要插入结点的位置,然后再和双亲结点比较,看看左子树还是右子树

  public boolean insert(int val){if(root==null){root=new TreeNode(val);return true;}TreeNode parent=null;TreeNode cur=root;while(cur!=null){if(cur.val>val){parent=cur;cur=cur.left;} else if (cur.val<val) {parent=cur;cur=cur.right;}else// 如果是等于就不能插入了,二叉排序树没办法容纳一样的key{return false;}}if(parent.val>val){parent.left=new TreeNode(val);}else{parent.right=new TreeNode(val);}return true;}

***************** 需要注意的是,二叉排序树不能插入重复的元素.*********************

 搜索元素

搜索元素也很简单,因为二叉排序树本身就是为了提高搜索效率而产生的,

  public  boolean search(int key){TreeNode cur=root;while(cur!=null){if(cur.val>key){cur=cur.left;}else if(cur.val<key){cur =cur.right;}else{return true;}}return false;}

 删除元素

  删除元素是比较难的,如果笔者自己想想就会发现,好像有好多种情况要去想,这里笔者也不绕弯子,前辈们已经替我们总结出来了,大致会有三种情况

但在分情况之前 首先:设待删除结点为 cur, 待删除结点的双亲结点为 parent, 其次,要确定,待删除结点是否存在.

public  boolean remove(int val){TreeNode parent=null;TreeNode cur=root;while(cur!=null){if(cur.val>val){parent=cur;cur=cur.left;}else if(cur.val<val){parent=cur;cur =cur.right;}else{// 找到了removeNode(cur,parent);return true;}}return false;}

 接下来我们完善 removeNode 

第一种情况,待删结点没有左子树

这种情况,我们就让它的右子树结点和双亲结点连接上就好了.

但也有个前提,他不是根节点,所以要考虑到这一点

代码如下:

   if(cur.left==null)// 左边为空{if(cur==root){root=root.right;return;}else if(cur==parent.left){parent.left=cur.right;return ;}else{parent.right=cur.right;return ;}}

 如果是双亲结点的左子树,就是  parent.left=cur.right;

 如果是双亲结点的右子树,就是  parent.right=cur.right;

第二种情况,待删结点没有右子树

同理,代码如下

      else if (cur.right==null)// 右边为空{if(cur==root){root=root.left;}else if(cur==parent.left){parent.left=cur.left;}else{parent.right=cur.left;}}

 第三种,左右都不为空

我们的思路:
1.找到 cur

2.找cur左子树最右边的或者cur右子树最左边的,来替换我们的这个cur结点

3.替换完成以后,再把结点删除,请注意,有两种可能.如图所示

 else{TreeNode ansparent = cur;TreeNode ans = cur.right;// 去找右子树最左边的while(ans.left!=null){ansparent=ans;ans=ans.left;}// 找到以后,也要分情况cur.val=ans.val;if(ansparent.left == ans){ansparent.left = ans.right;}else{ansparent.right=ans.right;}}

完整代码

package searchtree;public class SearchTree// 二叉搜索树
{static  class TreeNode{public  int val;public  TreeNode left;public  TreeNode right;public TreeNode(int val)   {this.val = val;}}public  TreeNode root;public  boolean search(int key){TreeNode cur=root;while(cur!=null){if(cur.val>key){cur=cur.left;}else if(cur.val<key){cur =cur.right;}else{return true;}}return false;}public boolean insert(int val){if(root==null){root=new TreeNode(val);return true;}TreeNode parent=null;TreeNode cur=root;while(cur!=null){if(cur.val>val){parent=cur;cur=cur.left;} else if (cur.val<val) {parent=cur;cur=cur.right;}else// 如果是等于就不能插入了,二叉排序树没办法容纳一样的key{return false;}}if(parent.val>val){parent.left=new TreeNode(val);}else{parent.right=new TreeNode(val);}return true;}public  boolean remove(int val){TreeNode parent=null;TreeNode cur=root;while(cur!=null){if(cur.val>val){parent=cur;cur=cur.left;}else if(cur.val<val){parent=cur;cur =cur.right;}else{// 找到了removeNode(cur,parent);return true;}}return false;}private void removeNode(TreeNode cur, TreeNode parent){if(cur.left==null)// 左边为空{if(cur==root){root=root.right;return;}else if(cur==parent.left){parent.left=cur.right;return ;}else{parent.right=cur.right;return ;}}else if (cur.right==null)// 右边为空{if(cur==root){root=root.left;}else if(cur==parent.left){parent.left=cur.left;}else{parent.right=cur.left;}}// 左右都不为空// 思路// 1.找到 cur// 2.找cur左子树最右边的或者cur右子树最左边的,来替换我们的这个cur结点else{TreeNode ansparent = cur;TreeNode ans = cur.right;// 去找右子树最左边的while(ans.left!=null){ansparent=ans;ans=ans.left;}// 找到以后,也要分情况cur.val=ans.val;if(ansparent.left == ans){ansparent.left = ans.right;}else{ansparent.right=ans.right;}}}
}

结尾

这一篇算是我的笔记,所以写的会比较潦草,提前sorry了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

40分钟学 Go 语言高并发:GC原理与优化

GC原理与优化 一、GC基础知识概览 方面核心概念重要性优化目标GC算法三色标记法、并发GC⭐⭐⭐⭐⭐理解GC工作原理垃圾回收策略触发条件、回收步骤⭐⭐⭐⭐⭐掌握GC过程GC调优参数设置、性能监控⭐⭐⭐⭐优化GC效果内存管理内存分配、内存逃逸⭐⭐⭐⭐⭐减少内存压力 让我们…

梯度爆炸与消失

梯度爆炸和梯度消失 一、概念解析 &#xff08;一&#xff09;梯度爆炸 定义 在深度神经网络训练的反向传播过程中&#xff0c;梯度爆炸是指梯度的值过大的现象。这会使模型的参数更新出现异常。 产生原因 深层网络与链式法则&#xff1a;深度神经网络按链式法则计算某层权重…

linux 文件权限,修改权限,系统调用

参考chmod 777 到底是啥 ???看完这个你就完全懂了&#xff01;-CSDN博客 ls -l 查看当前目录文件的权限 会有一个十位的东西 分别为 d:这是一个文件夹 后面3*3位分别表示所有者用户&#xff0c;同组用户&#xff0c;其他用户的读(r)&#xff0c;写(w)&#xff0c;执行(x)…

notepad++文件github下载

1、github下载网址&#xff1a;Releases notepad-plus-plus/notepad-plus-plus GitHub 2、找到操作系统支持的软件&#xff1a; 3、CSDN下载链接&#xff1a;https://download.csdn.net/download/u013083576/90046203

【Spark源码分析】基于Spark3.4.2源码分析SparkSQL执行过程

基于Spark3.4.2源码分析SparkSQL执行过程 文章目录 基于Spark3.4.2源码分析SparkSQL执行过程基本执行流程Unresolved逻辑计划树相关类RuleExector相关类 详细代码SparkSessionAbstractSqlParserDatasetQueryExecutionAnalyzerRuleExecutorCheckAnalysis 附录CTE简述SQL解析器Qu…

PHP和GD库如何根据像素绘制图形

使用PHP和GD库&#xff0c;你可以根据像素绘制各种图形&#xff0c;比如点、线、矩形、圆形等。GD库是PHP的一个扩展&#xff0c;它提供了一系列用于创建和处理图像的函数。以下是一个简单的示例&#xff0c;展示如何使用GD库根据像素绘制图形。 安装GD库 首先&#xff0c;确…

kafka admin client 如何计算kafka发送速度

文章目录 方法 1&#xff1a;使用 AdminClient 获取消息数量示例代码&#xff1a;计算 Kafka 生产速度代码解释&#xff1a;解释&#xff1a;结果示例&#xff1a;方法 2&#xff1a;使用 Kafka JMX 监控JMX 指标&#xff1a; 总结&#xff1a; 要使用 Kafka Admin Client 来计…

【CSS in Depth 2 精译_064】10.3 CSS 中的容器查询相对单位 + 10.4 CSS 容器样式查询 + 10.5 本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 10.1.1 容器尺寸查询的用法 10.2 深入理解容器 10.2.1 容器的类型10.2.2 容器的名称10.2.3 容器与模块化 CSS 10.3 与容器相关的单位 ✔…

适合写作中引用的名人名言 - 坚持与梦想 P1

概述 在写作中引用名人名言&#xff0c;有如下 3 大利 增强文章的权威性&#xff1a;名人名言往往是由历史上或当代具有广泛影响力的人物提出的&#xff0c;他们的言论经过时间的考验&#xff0c;是智慧的结晶 丰富文章内涵&#xff1a;名人名言往往言简意赅&#xff0c;蕴含…

TYUT设计模式精华版

七大原则 单一职责原则 职责要单一不能将太多的职责放在一个类中 开闭原则 软件实体对扩展是开放的&#xff0c;但对修改是关闭的 里氏代换原则 一个可以接受基类对象的地方必然可以接受子类 依赖倒转原则 要针对抽象层编程&#xff0c;而不要针对具体类编程 接口隔离原则 …

Java全栈:超市购物系统实现

项目介绍 本文将介绍如何使用Java全栈技术开发一个简单的超市购物系统。该系统包含以下主要功能: 商品管理用户管理购物车订单处理库存管理技术栈 后端 Spring Boot 2.7.0Spring SecurityMyBatis PlusMySQL 8.0Redis前端 Vue.js 3Element PlusAxiosVuex系统架构 整体架构 …

电阻的基本应用

从使用数量的角度来看&#xff0c;电阻在电子元器件中的数量要占到30%以上&#xff0c;电阻可以在电路中用于分压、分流、限流、负载、反馈、阻抗匹配、RC充放电电路、上下拉、运算放大器外围电路、兼容设计电路、电流转电压等&#xff0c;下面介绍一下电阻的基本应用 在集总参…

Z2400055 基于php+MYSQL化妆品公司网上商城系统的设计与实现 源码 文档 配置

化妆品公司网上商城系统 1.项目描述项目概述运行环境项目技术栈功能模块总结 5.源码获取 1.项目描述 项目概述 项目名称&#xff1a;化妆品公司网上商城系统 项目简介&#xff1a; 本项目旨在开发一个针对女性消费者的化妆品网上商城系统&#xff0c;采用PHP作为主要开发语言…

EXCEL截取某一列从第一个字符开始到特定字符结束的字符串到新的一列

使用EXCEL中的公式进行特定截取 假设列A是一组产品的编码&#xff0c;我们需要的数据是“-”之前的字段。 我们需要在B1单元格输入公式“LEFT(A1,SEARCH("-",A1)-1)”然后选中B1至B4单元格&#xff0c;按“CTRLD”向下填充&#xff0c;就可以得出其它几行“-”之前的…

postgresql导出/导入数据库

文章目录 导出数据库导出整个数据库导出特定表导出特定模式 导入数据库使用 psql 导入使用 pg_restore 导入 示例导出导入 注意事项 在 PostgreSQL 中&#xff0c;导出&#xff08;备份&#xff09;和导入&#xff08;恢复&#xff09;某个数据库可以使用 pg_dump 和 psql 或 p…

Cisco WebEx 数据平台:统一 Trino、Pinot、Iceberg 及 Kyuubi,探索 Apache Doris 在 Cisco 的改造实践

导读&#xff1a;Cisco WebEx 早期数据平台采用了多系统架构&#xff08;包括 Trino、Pinot、Iceberg 、 Kyuubi 等&#xff09;&#xff0c;面临架构复杂、数据冗余存储、运维困难、资源利用率低、数据时效性差等问题。因此&#xff0c;引入 Apache Doris 替换了 Trino、Pinot…

【链表】【删除节点】【刷题笔记】【灵神题单】

237.删除链表的节点 链表删除节点的本质是不用删除&#xff0c;只需要操作指针&#xff0c;跳过需要删除的节点&#xff0c;指向下下一个节点即可&#xff01; 删除某个节点&#xff0c;但是不知道这个节点的前一个节点&#xff0c;也不知道头节点&#xff01;摘自力扣评论区…

python基础(五)

正则表达式 在编写处理字符串的程序或网页时&#xff0c;经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说&#xff0c;正则表达式就是记录文本规则的代码。 符号解释示例说明.匹配任意字符b.t可以匹配bat / but / b#t / b1t等\…

高级java每日一道面试题-2024年11月29日-JVM篇-常见调优工具有哪些?

如果有遗漏,评论区告诉我进行补充 面试官: 常见调优工具有哪些? 我回答: 在Java高级面试中&#xff0c;调优是一个非常重要的主题。掌握一些常用的调优工具可以帮助开发者有效地分析和解决性能问题。下面是一些常见的Java调优工具及其详细说明&#xff1a; 1. JVM自带工具…

电机瞬态分析基础(7):坐标变换(3)αβ0变换,dq0变换

1. 三相静止坐标系与两相静止坐标系的坐标变换―αβ0坐标变换 若上述x、y坐标系在空间静止不动&#xff0c;且x轴与A轴重合&#xff0c;即&#xff0c;如图1所示&#xff0c;则为两相静止坐标系&#xff0c;常称为坐标系&#xff0c;考虑到零轴分量&#xff0c;也称为αβ0坐标…