当前位置: 首页 > news >正文

【数据结构】Java实现二叉搜索树

二叉搜索树的基本性质

二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,它具有以下特征:

1. 节点结构:每个节点包含一个键(key)和值(value),以及指向左子树和右子树的指针。

2. 左子树和右子树的性质:
   - 对于每个节点,左子树中所有节点的键都小于该节点的键。
   - 右子树中所有节点的键都大于该节点的键。
   - 这种特性使得二叉搜索树可以高效地进行查找、插入和删除操作。

3. 查找操作:从根节点开始,比较目标键与当前节点的键。如果目标键小于当前节点的键,则继续在左子树中查找;如果大于,则在右子树中查找。这个过程递归进行,直到找到目标节点或者到达树的叶子节点。

4. 插入操作:插入新节点时,同样从根节点开始,根据二叉搜索树的性质,选择左子树或右子树,直到找到一个空位置插入新节点。

5. 删除操作:删除节点较为复杂,分为三种情况:
   - 若被删除节点为叶子节点,直接移除。
   - 若被删除节点只有一个子节点,则用其子节点替代该节点。
   - 若被删除节点有两个子节点,则需要找到该节点的后继节点(通常是右子树中最小的节点),用其替代被删除的节点,并递归删除后继节点。

二叉搜索树的平均时间复杂度为O(log n),但在最坏情况下(如插入顺序导致树变为链表),其时间复杂度可达到O(n)。为了避免这一问题,通常会使用自平衡的二叉搜索树,如红黑树或AVL树。

二叉搜索树在许多应用中非常重要,包括数据库索引、内存中的排序数据以及许多算法实现等。

代码实现二叉搜索树的基本操作

查找操作

二叉搜索树(BST)中的查找操作是基于树的特性进行的,具体原理如下:

查找操作原理

  1. 初始化当前节点(cur):

    • 将当前节点设置为树的根节点(root),开始从树的顶端进行查找。
  2. 循环查找:

    • 使用while循环遍历树的节点,条件是cur不为null(即当前节点存在)。
  3. 比较当前节点与目标值:

    • 左子树查找:如果当前节点的值小于目标值,说明目标值可能在右子树中,因此将cur指向cur.right
    • 右子树查找:如果当前节点的值大于目标值,说明目标值可能在左子树中,将cur指向cur.left
    • 找到目标值:如果当前节点的值等于目标值,则查找成功,返回true
  4. 查找结束:

    • 如果循环结束,意味着没有找到目标值,此时返回false

代码实现:

public boolean search(int val) {// 初始化当前节点为根节点treeNode cur = root;// 当当前节点不为空时循环查找while (cur != null) {// 如果当前节点的值小于目标值,则在右子树继续查找if (cur.val < val) {cur = cur.right;// 如果当前节点的值大于目标值,则在左子树继续查找} else if (cur.val > val) {cur = cur.left;// 如果找到目标值,返回true} else {return true;}}// 如果遍历结束仍未找到目标值,返回falsereturn false;
}

查找操作利用了二叉搜索树的排序性质,能够在相对较短的时间内找到目标值。通过比较和递归向左或向右子树移动,该操作在实际应用中被广泛使用,例如在需要快速检索数据的系统中,如数据库和内存中的索引结构等。

插入操作

二叉搜索树(Binary Search Tree, BST)的插入操作是基于树的特性进行的,以下是插入操作的原理详解:

插入操作原理

  1. 开始插入

    • 从树的根节点开始进行插入操作。
  2. 比较键值

    • 对于当前节点,比较要插入的值(key)与当前节点的键(val):
      • 如果要插入的值小于当前节点的键,则应该将其插入到左子树中。
      • 如果要插入的值大于当前节点的键,则应该将其插入到右子树中。
      • 如果要插入的值等于当前节点的键,通常视为重复值,根据具体需求,可以选择不插入、更新值或者其他处理。
  3. 寻找空位

    • 将当前节点更新为其左子树或右子树,然后重复该过程,直到找到一个空位置(即当前节点为null)。
    • 该空位置即为将新值插入树中的位置。
  4. 插入新节点

    • 在找到的空位置创建新的节点,并将其插入到树中。

 代码实现:

    public boolean insert(int val) {treeNode node = new treeNode(val);if(root == null) {root = node;return true;}treeNode cur = root;treeNode parent = null;while(cur != null) {if(val > cur.val) {parent = cur;cur = cur.right;}else if(val < cur.val) {parent = cur;cur = cur.left;}else {return false;}}if(val > parent.val) {parent.right = node;}else {parent.left = node;}return true;}

插入操作遵循了二叉搜索树的基本特性,通过比较和递归地前进来在合适的位置插入新节点。这一操作是保持树的结构的关键,确保每次插入后都能满足二叉搜索树的性质,以便后续的查找、删除等操作更加高效。

删除操作

  1. 查找要删除的节点

    • 从根节点开始,通过与当前节点的值比较,找到目标节点。如果目标值大于当前节点值则继续查找右子树;如果小于,则查找左子树。同时记录当前节点的父节点。
  2. 执行删除操作

    • 一旦找到要删除的节点,调用removeNode方法,根据要删除节点的子节点情况执行不同的删除逻辑。

代码实现:

public void remove(int key) {treeNode cur = root;        // 当前节点初始化为根节点treeNode parent = null;     // 记录当前节点的父节点// 找到要删除的节点while(cur != null) {if(key > cur.val) {parent = cur;       // 更新父节点cur = cur.right;    // 向右子树查找} else if(key < cur.val) {parent = cur;       // 更新父节点cur = cur.left;     // 向左子树查找} else {// 找到目标节点,执行删除逻辑removeNode(parent, cur);return;            // 找到并删除后退出}}System.out.println("没有该节点"); // 如果节点未找到,输出提示信息
}// 执行删除操作的方法
private void removeNode(treeNode parent, treeNode cur) {// 情况1:要删除的节点没有左子节点if(cur.left == null) {if(cur == root) {root = cur.right;  // 如果要删除的节点是根节点,更新根节点} else if(cur == parent.left) {parent.left = cur.right; // 更新父节点的左子指针} else {parent.right = cur.right; // 更新父节点的右子指针}}// 情况2:要删除的节点没有右子节点else if(cur.right == null) {if(cur == root) {root = cur.left;   // 如果要删除的节点是根节点,更新根节点} else if(cur == parent.left) {parent.left = cur.left; // 更新父节点的左子指针} else {parent.right = cur.left; // 更新父节点的右子指针}}// 情况3:要删除的节点有两个子节点else {// 找到要删除节点的右子树中的最小节点treeNode target = cur.right;treeNode targetParent = cur;// 寻找右子树中最小节点while(target.left != null) {targetParent = target; // 更新最小节点的父节点target = target.left;   // 持续向左查找}// 用找到的最小节点的值替代要删除的节点的值cur.val = target.val;// 删除最小节点if(target == targetParent.right) {targetParent.right = target.right; // 更新父节点的右子指针} else {targetParent.left = target.right;  // 更新父节点的左子指针}}
}
  1. 查找节点

    • 使用while循环查找目标节点,记录其父节点,以便于后续的删除操作。比较节点值,并依据结果移动到左或右子树。
  2. 删除逻辑

    • 没有左子节点:直接将右子节点连接到父节点,删除当前节点。
    • 没有右子节点:直接将左子节点连接到父节点,同样删除当前节点。
    • 有两个子节点:找到右子树中最小的节点(后继节点),用其值替代当前节点的值,然后递归删除后继节点。
  3. 输出信息

    • 如果在树中找不到目标节点,输出“没有该节点”提示。

性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:\log _{2}^{n}
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:\frac{n}{2}

相关文章:

【数据结构】Java实现二叉搜索树

二叉搜索树的基本性质 二叉搜索树&#xff08;Binary Search Tree, BST&#xff09;是一种特殊的二叉树&#xff0c;它具有以下特征&#xff1a; 1. 节点结构&#xff1a;每个节点包含一个键&#xff08;key&#xff09;和值&#xff08;value&#xff09;&#xff0c;以及指…...

钉钉小程序如何通过setdate重置对象

在钉钉小程序中&#xff0c;通过setData方法来重置对象&#xff08;即更新对象中的数据&#xff09;是一个常见的操作。然而&#xff0c;需要注意的是&#xff0c;钉钉小程序&#xff08;或任何小程序平台&#xff09;的setData方法在处理对象更新时有一些特定的规则和最佳实践…...

DjangoRF-10-过滤-django-filter

1、安装pip install django-filter https://pypi.org/ 搜索django-filter基础用法 2、进行配置 3、进行内容调试。 4、如果碰到没有关联的字段。interfaces和projects没有直接关联字段&#xff0c;但是interface和module有关联&#xff0c;而且module和projects关联&#x…...

Android SurfaceFlinger——GraphicBuffer的生成(三十二)

通过前面的学习我们知道,在 SurfaceFlinger 中使用的生产者/消费者模型,Surface 做为生产者一方存在如下两个比较重要的函数: dequeueBuffer:获取一个缓冲区(GraphicBuffer),也就是 GraphicBuffer 生成。queueBuffer :把缓冲区(GraphicBuffer)放入缓冲队列中。 …...

<数据集>棉花识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;13765张 标注数量(xml文件个数)&#xff1a;13765 标注数量(txt文件个数)&#xff1a;13765 标注类别数&#xff1a;4 标注类别名称&#xff1a;[Partially opened, Fully opened boll, Defected boll, Flower] 序…...

[240730] OpenAI 推出基于规则的奖励机制 (RBR) 提升模型安全性 | 英特尔承认其13、14代 CPU 存在问题

目录 OpenAI 推出基于规则的奖励机制&#xff08;RBR&#xff09;提升模型安全性英特尔承认其 13、14代 CPU 存在问题 OpenAI 推出基于规则的奖励机制&#xff08;RBR&#xff09;提升模型安全性 为了解决传统强化学习中依赖人工反馈的低效问题&#xff0c;OpenAI 开发了基于规…...

【JavaScript】展开运算符详解

文章目录 一、展开运算符的基本用法1. 展开数组2. 展开对象 二、展开运算符的实际应用1. 合并数组2. 数组的浅拷贝3. 合并对象4. 对象的浅拷贝5. 更新对象属性 三、展开运算符的高级用法1. 在函数参数中使用2. 嵌套数组的展开3. 深拷贝对象4. 动态属性名 四、注意事项和最佳实践…...

麒麟V10系统统一认证子系统国际化

在适配麒麟V10系统统一认证子系统国际化过程中&#xff0c; 遇到了很多的问题&#xff0c;关键是麒麟官方的文档对这部分也是粗略带过&#xff0c;遇到的问题有: &#xff08;1&#xff09;xgettext无法提取C源文件中目标待翻译的字符串。 &#xff08;2&#xff09;使用msgf…...

C语言进阶 13. 文件

C语言进阶 13. 文件 文章目录 C语言进阶 13. 文件13.1. 格式化输入输出13.2. 文件输入输出13.3. 二进制文件13.4. 按位运算13.5. 移位运算13.6. 位运算例子13.7. 位段 13.1. 格式化输入输出 格式化输入输出: printf %[flags][width][.prec][hlL]type scanf %[flags]type %[fl…...

LinuxCentos中ELK日志分析系统的部署(详细教程8K字)附图片

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…...

Vscode ssh Could not establish connection to

错误表现 上午还能正常用vs code连接服务器看代码&#xff0c;中午吃个饭关闭vscode再重新打开输入密码后就提示 Could not establish connection to xxxx 然后我用终端敲ssh的命令连接&#xff0c;结果是能正常连接。 解决方法 踩坑1 网上直接搜Could not establish con…...

数字陷波器的设计和仿真(Matlab+C)

目录 一、数字陷波器的模型 二、Matlab仿真 1. 示例1 2. 示例2 三、C语言仿真 1. 由系统函数计算差分方程 2. 示例代码 一、数字陷波器的模型 二、Matlab仿真 1. 示例1 clear clc f0=100;%滤掉的100Hz fs=1000;%大于两倍的信号最高频率 r=0.9; w0=2*pi*f0/fs;%转换到…...

[玄机]流量特征分析-常见攻击事件 tomcat

题目网址【玄机】&#xff1a;https://xj.edisec.net/ Tomcat是一个开源的Java Servlet容器&#xff0c;它实现了Java Servlet和JavaServer Pages (JSP) 技术&#xff0c;提供了一个运行这些应用程序的Web服务器环境。Tomcat由Apache软件基金会的Jakarta项目开发&#xff0c;是…...

【TOOLS】Project 2 Maven Central

发布自己的项目到maven中央仓库 Maven Central Account 访问&#xff1a;https://central.sonatype.com/&#xff0c;点击右上角&#xff0c;根据提示注册账号 构建User token &#xff0c;用于访问中央仓库的API&#xff1a; 点击右上角&#xff0c;查看账户点击Generate Us…...

【Opencv】模糊

消除噪声 用该像素周围的平均值代替该像素值 4个函数 blur():最经典的 import os import cv2 img cv2.imread(os.path.join(.,dog.jpg)) k_size 7 #窗口大小&#xff0c;数字越大&#xff0c;模糊越强 img_blur cv2.blur(img,(k_size,k_size)) #窗口是正方形&#xff…...

函数式编程范式

文章目录 函数式编程范式不可变性&#xff08;Immutable&#xff09;纯函数&#xff08;Pure Functions&#xff09;函数作为一等公民&#xff08;First-Class Functions&#xff09;高阶函数&#xff08;Higher-Order Functions函数组合&#xff08;Function Composition&…...

特征缩放的秘籍:sklearn中的数据标准化技术

特征缩放的秘籍&#xff1a;sklearn中的数据标准化技术 在机器学习中&#xff0c;特征缩放&#xff08;Feature Scaling&#xff09;是数据预处理的重要步骤&#xff0c;它确保了不同量纲和范围的特征在模型训练中具有相同的重要性。Scikit-learn&#xff08;简称sklearn&…...

hdfs文件系统

简述什么是HDFS&#xff0c;以及HDFS作用 &#xff1f; HDFS在Hadoop中的作用是为海量的数据提供了存储&#xff0c;能提供高吞吐量的数据访问&#xff0c;HDFS有高容错性的 特点&#xff0c;并且设计用来部署在低廉的硬件上&#xff1b;而且它提供高吞吐量来访问应用程序的数…...

基于STM32设计的个人健康检测仪(华为云IOT)(191)

基于STM32设计的个人健康检测仪(华为云IOT)(191) 文章目录 一、设计需求1.1 设计需求总结1.2 设计思路【1】整体设计思路【2】整体构架【3】ESP8266模块配置【4】上位机开发思路【5】供电方式1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】课题研究的意义【…...

面试:CUDA Tiling 和 CPU tiling 技术详解

目录 一、CUDA Tiling 和 CPU Tiling 技术概述 &#xff08;一&#xff09;技术原理 &#xff08;二&#xff09;应用场景 &#xff08;三&#xff09;优势和劣势 二、Tiling 技术在深度学习中的应用 三、Tiling 技术的缺点 一、CUDA Tiling 和 CPU Tiling 技术概述 Til…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

Yii2项目自动向GitLab上报Bug

Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...

VUE3 ref 和 useTemplateRef

使用ref来绑定和获取 页面 <headerNav ref"headerNavRef"></headerNav><div click"showRef" ref"buttonRef">refbutton</div>使用ref方法const后面的命名需要跟页面的ref值一样 const buttonRef ref(buttonRef) cons…...