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

news2024/11/18 17:48:22

目录

🎈概念

🎈操作-查找

🎈操作-插入

🎈操作-删除(难点)


🎈概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 :
  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

二叉搜索树  左<根<右

{5,3,4,1,7,8,2,6,0,9} 如何创建成上面的二叉搜索树,使每个子树的左孩子<根<右孩子(前提是左孩子和右孩子都不为空的情况下)

🎈操作-查找

我们根据上述的红色文字进行搜索查找。

 public boolean search(int key) {
        TreeNode cur = root;
        while (cur != null) {
            //如果值小于关键字,那么去二叉树的右边
            if (cur.val < key) {
                cur = cur.right;
                //如果值大于关键字,那么去二叉树的左边
            } else if (cur.val > key) {
                cur = cur.left;
            } else {
                return true;
            }
        }
        return false;
    }

🎈操作-插入

思路:如果这个树是空树,我们就直接插入

           如果这个树不是空树,按照查找的逻辑进行插入位置,插入新结点。

  • 如果根节点==val 返回false 
  • 如果根节点< val  去cur左子树查找
  • 如果根节点>val   去cur右子树查找

cur==null的时候,我们就要插入该节点(但是我们发现,如果遇到cur==null的时候,cur到了空的地方去,那谁记录cur的父节点呢?怎么给节点给cur所在位置呢?

我来用图给你们展示一下

此时我们通过cur=cur.left ,cur到了null的位置,然后我们要进行,插入值,该如何插入呢,此时我们就得给cur的父节点也记录下来,然后让node=parent.left。


    /**
     * 插入
     *
     * @param val
     * @return true 表示插入成功, false 表示插入失败
     */
    public boolean insert(int val) {
        //如果是空树,那么就将val直接给根
        if (root == null) {
            root = new TreeNode(val);
            return true;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {
            if (val < cur.val) {
                parent = cur;
                cur = cur.left;
            } else if (val > cur.val) {
                parent = cur;
                cur = cur.right;
            } else {
                return false;
            }
        }
        //上面并没有将新的节点插入进去
        //我们看到上面不管是cur.right还是cur.left赋值给cur后,cur=null,此时的值并没有插入进行,而是判空结束了
        TreeNode node = new TreeNode(val);
        if (parent.val > val) {
            //插入到左边
            parent.left = node;
        } else {
            parent.right = node;
        }
        //我们看到parent的作用其实就是当cur==null的时候
        //我们需要插入
        return true;
    }

🎈操作-删除(难点)

设待删除结点为 cur, 待删除结点的双亲结点为 parent

1. cur.left == null
  • 1. cur root,则 root = cur.right
  • 2. cur 不是 rootcur parent.left,则 parent.left = cur.right
  • 3. cur 不是 rootcur parent.right,则 parent.right = cur.right
如果cur的左边空
cur在parent的左边,但是cur的左边空,那么我们将cur的右边节点给parent的左边
cur在parent的右边,但是cur的左边空,那么我们将cur的右边节点给parent的右边
(cur在parent的哪一边,就将cur左右哪一个不为空的节点给parent的哪一边)
2. cur.right == null
  • 1. cur root,则 root = cur.left
  • 2. cur 不是 rootcur parent.left,则 parent.left = cur.left
  • 3. cur 不是 rootcur parent.right,则 parent.right = cur.left

cur左边为空,那么就将cur的左边节点 要么给parent的左边,那么parent的右边 //(取决于 cur在parent的哪一边)

3. cur.left != null && cur.right != null
  • 1. 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题
要么在左树中找到最大值(左数最右边的值),要么在右数找到最小值(右数最左边值)



我们最终的目的是让cur的右节点给cur,然后让cur指向cur的右树的最大值。

这种情况下我们就要将,6给cur,然后让原先6对应的值置空。


用tp记录cur的位置,然后t是tp的右孩子,为什么选择右孩子呢?因为我们要删除cur对应的值,那么我们就有俩种选择  (要么cur左边的最大值,要么cur右边的最小值)

此时我选择是找cur右边的最小值进行。

t是cur的右边,然后我们要先判断一下 是否t的左边为不为空,如果不为空,那么我们就要进入左边,因为二叉搜索树的特点就是 左孩子<根节点<右孩子,所以我们当初就是要找到cur的右边的最小值,就是一直往cur右孩子的左边找,不为空,那么我们就要将6赋值给cur,然后让置空即可。

如果下面还有值,如果右节点有值,那么就将那个右值赋值,如果左节点有值,那么就将左值赋值。


    public void remove(int key){
        //移除之前我们需要找到这个key
        TreeNode cur = root;
        TreeNode parent=cur;
        while (cur != null) {
            //如果值小于关键字,那么去二叉树的右边
            if (cur.val < key) {
                parent=cur;
                cur = cur.right;
                //如果值大于关键字,那么去二叉树的左边
            } else if (cur.val > key) {
                parent=cur;
                cur = cur.left;
            } else {
              //开始删除
                removeNode(cur,parent);
            }
        }
    }
    public void removeNode(TreeNode cur,TreeNode parent){
        if(cur.left==null){
            //左树空
            if(cur==root){
                root=cur.right;
            } else if (cur==parent.left) {
                parent.left=cur.right;
            }else{
                parent.right=cur.right;
            }
            //如果cur的左边空
            //cur在parent的左边,但是cur的左边空,那么我们将cur的右边节点给parent的左边
            //cur在parent的右边,但是cur的左边空,那么我们将cur的右边节点给parent的右边
            //(cur在parent的哪一边,就将cur左右哪一个不为空的节点给parent的哪一边)
        } 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;
            }
            //cur左边为空,那么就将cur的左边节点 要么给parent的左边,那么parent的右边
            //(取决于 cur在parent的哪一边)
        } else {

            //要么在左树中找到最大值(左数最右边的值)
            //要么在右数找到最小值(右数最左边值)

            //cur俩边都不为空
            TreeNode tp=cur;
            TreeNode t=cur.right;
            //此时的cur'是关键字,cur的左右俩边都不为空,我们要将cur的右边值给到cur
            // (cur右节点的左节点不为空,我们就将
            if(t.left!=null){
                tp=t;
                t=t.left;
            }
            cur.val=t.val;
            //删除t
            //如果t在tp左边,将t的右边值给tp左边
            //如果t在tp右边,将t的右边值给tp的右边
            if(tp.left==t){
                tp.left=t.right;
            }else{
                tp.right=t.right;
            }
        }
    }

今天张老师生病了。

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

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

相关文章

【Qt学习笔记】(四)Qt窗口

Qt窗口 1 菜单栏1.1 创建菜单栏1.2 在菜单栏中添加菜单1.3 创建菜单项1.4 在菜单项之间添加分割线1.5 给菜单项添加槽函数1.6 给菜单项添加快捷键 2 工具栏2.1 创建工具栏2.2 设置停靠位置2.3 设置浮动属性2.4 设置移动属性2.5 添加 Action 3 状态栏3.1 状态栏的创建3.2 在状态…

Matlab 机器人工具箱 动力学

文章目录 R.dynR.fdynR.accelR.rneR.gravloadR.inertiaR.coriolisR.payload官网:Robotics Toolbox - Peter Corke R.dyn 查看动力学参数 mdl_puma560; p560.dyn;%查看puma560机械臂所有连杆的动力学参数 p560.dyn(2);%查看puma560机械臂第二连杆的动力学参数 p560.links(2)…

mac命令行下计算文件SHA-256散列值

源起 从国内的第三方网站下载了Android sutiod的zip包下载地址&#xff0c;为了安全起见还是得跟Android官网上的对应的zip包的SHA值做下对比。以前是经常使用md5命令的&#xff0c;所以理论在命令行下应该是有对应的命令行工具可以计算SHA值的。后来搜索到可以用 shasum命令来…

Java中线程安全的集合类

在先前的文章中我们已经讲过了原子类(线程安全的基本类型&#xff0c;基于CAS实现)&#xff0c;详见常见锁策略&#xff0c;synchronized内部原理以及CAS-CSDN博客 &#xff0c;我们在来讲一下集合类&#xff0c;在原来的集合类&#xff0c;大多数是线程不安全的&#xff0c;虽…

深入了解 Android 中的 RelativeLayout 布局

RelativeLayout 是 Android 中常用的布局之一&#xff0c;它允许开发者基于子视图之间的相对位置来排列界面元素。在这篇博客中&#xff0c;我们将详细介绍 RelativeLayout 的各种属性&#xff0c;并提供代码示例和解释。 第一个示例 <RelativeLayoutandroid:layout_width…

【数据分享】2001~2023年中国区域MOD17A3HGF GPP数据

各位同学们好&#xff0c;今天和大伙儿分享的是2001~2023年中国区域MOD17A3HGF GPP数据。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或评论。 Running, S., M. Zhao. <i>MODIS/Terra Net Primary Production Gap-Filled Yearly L4 Global 500m SIN Grid…

标准库`random`函数大全:探索Python中的随机数生成【第107篇—`random`函数大全】

标准库random函数大全&#xff1a;探索Python中的随机数生成 随机数在计算机科学和数据科学领域中扮演着重要角色&#xff0c;Python的标准库中提供了random模块&#xff0c;用于生成各种随机数。本篇博客将深入探讨random模块的各种函数&#xff0c;以及它们的应用场景和代码…

Leetcoder Day35| 动态规划part02

62.不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff…

如何在2.2.1版Aduino IDE中开发ESP32

ESP32芯片集成了WIFI和蓝牙&#xff0c;而且关于生态也很不错&#xff0c;越来越多的学习者和开发者选择此类芯片&#xff0c;而不像用keil开发STM32或者51一样&#xff0c;ESP32虽然也有官方的ESP32-IDF开发软甲&#xff0c;但是经过我个人的实操体验&#xff0c;不适合小白或…

基于Springboot的人事管理系统 (有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的人事管理系统 &#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&am…

ctf_show笔记篇(web入门---文件包含)

目录 文件包含 78-79&#xff1a;最基础的文件包含&#xff0c;使用伪协议&#xff0c;大小写绕过或者通配符绕过&#xff0c;再或者使用其他方法 ​编辑80-81&#xff1a;可采用日志文件绕过或者大小写绕过&#xff08;81只能日志文件绕过&#xff09; ####80-86&#xff1…

linux系统---nginx(3)核心配置指令及调优

目录 Nginx 核心配置指令 一、Nginx配置文件详解 1、配置文件目录 2、配置文件结构 二、调优 1、在全局域进行的调优 1.1线程池指令 1.2 工作进程数指令 2.1 工作进程并非数指令 2.2 事件处理机制选择指令 2.3 互斥锁指令 3、在http指令域的调优 3.1 Nginx端口监听…

无所不谈,百无禁忌,Win11本地部署无内容审查中文大语言模型CausalLM-14B

无内容审查机制大模型整合包,基于CausalLM-14B量化 目前流行的开源大语言模型大抵都会有内容审查机制&#xff0c;这并非是新鲜事&#xff0c;因为之前chat-gpt就曾经被“玩”坏过&#xff0c;如果没有内容审查&#xff0c;恶意用户可能通过精心设计的输入&#xff08;prompt&a…

leetcode刷题记录:动态规划02,子序列问题

参考labuladong的算法小抄整理 link 子序列问题&#xff0c;用一维dp数组或二维dp数组来解决。 一维数组&#xff1a;最大子数组和&#xff0c;最长递增子序列。dp[i]的定义&#xff1a;在子数组 arr[0…i] 中&#xff0c;以 arr[i] 结尾的子序列的长度是 dp[i]。二维数组&…

【Vue3】解锁Vue3黑科技:探索接口、泛型和自定义类型的前端奇迹

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

【大数据架构(3)】Lambda vs. Kappa Architecture-选择你需要的架构

文章目录 一. Data Processing Architectures1. Lambda Architecture1.1. 架构说明a. Data Ingestion Layerb. Batch Layer (Batch processing)c. Speed Layer (Real-Time Data Processing)d. Serving Layer 1.2. Lambda Architecture的优缺点1.3. 使用案例 2. Kappa Architect…

【风格迁移】StyTr2:引入 Transformer 解决 CNN 在长距离依赖性处理不足和细节丢失问题

StyTr2&#xff1a;引入 Transformer 解决 CNN 在长距离依赖性处理不足和细节丢失问题 提出背景StyTr2 组成StyTr2 架构 提出背景 论文&#xff1a;https://arxiv.org/pdf/2105.14576.pdf 代码&#xff1a;https://github.com/diyiiyiii/StyTR-2 问题&#xff1a; 传统的神经…

NOC2023软件创意编程(学而思赛道)python初中组初赛真题

软件创意编程 一、参赛范围 1.参赛组别:小学低年级组(1-3 年级)、小学高年级组(4-6 年级)、初中组。 2.参赛人数:1 人。 3.指导教师:1 人(可空缺)。 4.每人限参加 1 个赛项。 组别确定:以地方教育行政主管部门(教委、教育厅、教育局) 认定的选手所属学段为准。 二、…

云主机和传统主机到底有什么区别呢?

随着信息技术的快速发展&#xff0c;企业对IT基础设施的要求越来越高&#xff0c;许多问题等待解决&#xff1a;政府传统部署扩容升级麻烦、公司服务器维护周期长、建设和维护成本低等。运营成本高&#xff1b; 安全稳定性差、数据易丢失等问题亟待解决。 云主机的出现很大程度…

蓝桥杯集训·每日一题2024 (前缀和)

笔记&#xff1a; 例题&#xff1a; #include<bits/stdc.h> using namespace std; const int N 5000010; char str[N]; int s[N]; int main(){int t;cin>>t;for(int a1;a<t;a){int n;cin>>n;scanf("%s",str1);for(int i1;i<n;i){s[i]s[i-1]…