数据结构之二叉搜索树底层实现洞若观火!

目录

题外话

正题

二叉搜索树

底层实现

二叉搜索树查找操作

查找操作思路

查找代码实现详解

二叉搜索树插入操作

插入操作思路

插入代码详解

二叉搜索树删除操作

删除操作思路

删除代码详解

小结


题外话

我的一切都是党给的,都是人民给的,都是家人们给的!!

十分感谢家人们的大力支持,没有你们就没有我的今天(作者磕头三响!!!)

正题

今天来复习一下二叉搜索树正好完成一下底层实现

二叉搜索树

二叉搜索树概念:如果一颗二叉搜索树的任一结点的左子树不为空,那么左子树一定比该结点值小

                          如果一颗二叉搜索树的任一结点的右子树不为空,那么右子树一定比该结点值大

如下图,就是一颗二叉搜索树

任一一颗二叉搜索树中序遍历一定是有序的

底层实现

我们先将搜索二叉树的结点和结点值,还有左右子树创建出来

static  class TreeNode
{
    //创建结点元素值val
    public int val;


    //创建搜索二叉树的左右子树
    public TreeNode left;
    public TreeNode right;


    //通过TreeNode的构造方法赋值val
    public TreeNode(int val)
    {
        this.val=val;
    }

}
    //创建搜索二叉树的根
    public TreeNode root;

二叉搜索树查找操作

查找操作思路

我们通过搜索二叉树的概念,让key和根结点值比较

如果比根结点大,就和根结点右子树比较

如果比根结点小就和根结点左子树比较

例如上图,key等于9的时候在图中能找到9的结点

而当key等于10的时候,走到结点值为9的位置后左右结点为空,所以找不到等于10的结点返回flase

所以可以很容易写出以下代码

查找代码实现详解

public boolean search(int key)
{
    //将根结点赋值给cur,防止遍历完成找不到搜索二叉树的根节点
    TreeNode cur=root;


    //当cur不为空
    while (cur!=null)
    {


        //如果cur的val值小于key说明key在cur的右边
        if (cur.val<key)
        {
            //cur等于cur的右子树
           cur=cur.right;
        }
        //如果cur的val值比key大,说明key在cur的左边
        else if (cur.val>key)
        {
            //cur等于cur的左子树
            cur=cur.left;
        }
        //如果cur的val值等于key,说明找到了,则返回true
        else {
            return true;
        }
    }
    //如果cur为空还没有找到key说明key在搜索二叉树中不存在返回false
    return false;
}

二叉搜索树插入操作

插入操作思路

1.如果根结点为空,直接让插入元素val插入到根结点位置

2.如果根结点不为空

如果val大于根结点则继续判断root右子树和val大小关系

如果val小于根结点则继续判断root左子树和val大小关系

3.如下图所示,当我们走到结点值为9的位置发现val=10仍然大于9

然后继续往9的右子树走,发现为空

我们将val=10插入9的右子树,但是我们没有记录9这个结点,无法向9这个结点的右子树插入val

所以我们需要记录最近一次到达的上一个结点,以便可以将结点连接在一起

4.如果val是二叉搜索树中的结点值其中之一

比如val=5,这无法插入

因为二叉搜索树中的元素一定是没有重复的

要么比任意结点小,要么比任意结点大

不可能出现两个结点相同的情况

所以当出现插入元素和二叉搜索树中元素相同时,我们选择返回false

插入代码详解

public boolean insert(int val)
{
    //如果根结点为空则将插入结点作为根结点
    if (root==null)
    {
        root=new TreeNode(val);
        return true;
    }
    //如果根结点不为空,将root赋值给cur
    TreeNode cur=root;
    //创建prent记录cur到达的上一个结点
    TreeNode parent=null;
    //当cur不为空
    while (cur!=null) {
        //如果cur的val值比插入值小,则让parent记录当前cur结点,并且cur等于cur的右子树
        if (cur.val < val) {
            parent=cur;
            cur = cur.right;
        }
        //如果cur的val值比插入值大,则让parent记录当前cur结点,并且cur等于cur的左子树
        else if (cur.val > val) {
            parent=cur;
            cur = cur.left;
        }
        //如果cur的val值等于插入值,则无法插入,返回false
        else {
            return false;
        }
    }
    //当cur==null说明cur已经到达了要插入的位置
    TreeNode node=new TreeNode(val);
    //如果插入值比cur到达的上一个结点值大,则插入在上一个结点值的右边
    if (val> parent.val)
    {
        parent.right=node;
    }
    //如果插入值比cur到达的上一个结点值小,则插入在上一个结点值的左边
    else {
        parent.left=node;
    }
    //最后插入完成返回true
    return true;
}

接下来讲解一下搜索二叉树删除操作(有点难)

大家跟紧我的思维!

二叉搜索树删除操作

删除操作思路

首先咱们思考一下,删除搜索二叉树结点元素我们需要考虑什么问题

1.首先要遍历搜索二叉树找到要删除的结点

2.考虑搜索二叉树为空,没有结点的情况,无法删除

3.考虑搜索二叉树删除结点的左子树为空的情况如下图,cur为要删除结点

4.考虑搜索二叉树删除结点的右子树为空的情况,这里就不展示了,和上面情况差不多

5.考虑搜索二叉树删除结点的左子树右子树都不为空的情况(认真理解)

这里统一采用找到删除结点的右子树最深左结点的方法

找到get分两种情况下图是第一种

下图是第二种

以上内容我最开始也想不出来,但是做多了关于二叉树的题之后,也渐渐找到了这类型题的规律

基本上任何二叉树的题都和遍历二叉树有关系,也就是在遍历二叉树的基础上

无非是比较结点大小,或者结点是否存在等等变化,大家可以试着体会一下

删除代码详解

这里用了两个方法

1.第一个方法是找到要删除的结点

2.第二个方法是接收要删除的结点,以及遍历的上一个结点值

//这个方法是用来找到要删除的结点,并调用删除结点方法

public boolean remove(int val)
{
    //当二叉搜索树为空树,则返回false
    if (root==null)
    {
        return false;
    }
    //让root赋值给cur去遍历二叉搜索树
    TreeNode cur=root;
    //设置parent记录上一个遍历的结点
    TreeNode parent=null;
    //当cur不等于空就继续找删除结点
    while (cur!=null) {
        //如果cur的val值比删除值小,则让parent记录当前cur结点,并且cur等于cur的右子树
        if (cur.val < val) {
            parent=cur;
            cur = cur.right;
        }
        //如果cur的val值比删除值大,则让parent记录当前cur结点,并且cur等于cur的左子树
        else if (cur.val > val) {
            parent=cur;
            cur = cur.left;
        }
        //如果cur的val值等于删除值,则说明cur所在就是要删除的结点
        // 则调用remoNode方法,传入删除结点cur和parent
        else {
            removeNode(cur,parent);
            return true;
        }

    }
    //当cur等于空就说明二叉搜索树中不存在删除结点,返回false
    return false;
}

//这个方法负责接收要删除的结点和上一个到达的结点,并删除结点值

private void removeNode(TreeNode cur,TreeNode parent)
{
    //一.如果要删除结点的左子树为空(三种情况)
    if (cur.left==null)
    {
        //1.如果根结点等于要删除结点cur
        if (root==cur)
        {
            //让root指向root的右子树
            root=root.right;
        }
        //2.如果cur为parent的左子树
        else if (cur==parent.left)
        {
            //则让parent的左子树指向cur.right的右子树
            parent.left=cur.right;
        }
        //3.如果cur为parent的右子树
        else {
            //则让parent的右子树指向cur的右子树
            parent.right=cur.right;
        }
    }
    //二.当要删除结点cur的右子树为空时(三种情况)
    else if (cur.right==null)
    {
        //1.如果cur等于根结点
        if (cur==root)
        {
            //让根结点指向cur的左子树
            root=cur.left;
        }
        //2.如果cur等于parent的左子树
        else if(cur==parent.left)
        {
            //则让parent的左子树指向cur的左子树
            parent.left=cur.left;
        }
        //3.如果cur等于parent的右子树
        else {
           //则让parent的右子树指向cur的左子树
            parent.right=cur.left;
        }
    }
    //三.如果左子树右子树都不为空
    else {
        //设置getParent指向cur,设置get指向cur的右子树
        TreeNode getParent=cur;
        TreeNode get=cur.right;
        //如果get的左子树不为空,就去找到cur.right的最深左结点,并让getPatent记录上一个到达的结点
        while (get.left!=null)
        {
            getParent=get;
            get=get.left;
        }
        //当get左子树为空,说明找到了最深左结点,让get的val覆盖cur的val
        cur.val=get.val;
        //如果cur.right有左子树,getParent的左子树一定会等于get结点
        if (getParent.left==get)
        {
            //get不可能有左子树了,所以直接让getParent左子树指向get的右子树,图中第一种情况
            getParent.left=get.right;
        }
        //如果cur.right没有左子树,直接让getParent的右子树指向get的右子树即可,图中第二种情况
        else {
            getParent.right=get.right;
        }
    }
}

小结

今天是真的超级努力

早上从10点多起床,洗漱然后吃饭,从十一点半学到了现在,七个多小时,晚上还有课三个小时

最热爱的一集!!

麻烦喜欢的家人们给个三连好嘛!!!(点赞关注收藏!!!)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA使用中, 设置平展软件包。使用IDEA遇到的问题:src里为什么创建包为什么不在包里面

使用IDEA遇到的问题&#xff1a;src里为什么创建包为什么不在包里面 如下图所示 &#xff1a; 点击齿轮设置 如何搞回来&#xff1f; 看下面的Flatten Packages&#xff08;平展软件包&#xff09;取消掉。

C++学习之C++11标准

目录 一&#xff0c;列表初始化 二&#xff0c;initializer_list 三&#xff0c;auto与decltype 1&#xff09;auto 2&#xff09;decltype 四&#xff0c;nullptr 五&#xff0c;范围for 六&#xff0c;新加容器 1&#xff09;array 2&#xff09;forward_list 3&a…

Zabbix 监控系统:监控Windows端

目录 前言 1、zabbix Windows客户端安装包下载 2、安装zabbix Windows客户端 3、 查看zabbix.Agent是否正在运行 4、Zabbix Web 界面配置 5、模拟故障&#xff08;关闭Windows 10机器&#xff09; 6、Zabbix Web 界面验证故障信息 前言 Zabbix是一种开源的网络监控系统…

小扎万字深度访谈:最强开源大模型Llama 3发布,Meta的AGI路径和开源哲学

今天Meta发布了史上最强开源大模型Llama 3&#xff0c;一口气发布了 8B 和 70B 2个预训练和指令微调模型&#xff0c;对比同级别的参数模型&#xff0c;性能上均达到了最佳。 此外&#xff0c;Meta还发布了基于Llama 3的AI助手Meta AI&#xff0c;可以在Facebook、Instagram、W…

优化器与优化策略的搭配

在深度学习中不同的optimizer 通常会选择不同 优化策略 lr_sheduler 与之搭配&#xff1b; 1. SGD 与 Adam 优化器 Adam 与经典 SGD 的不同之处在于&#xff0c; Adam 执行局部参数更新&#xff08;即在参数级别进行更改&#xff09;&#xff0c;而不是全局执行此操作的 SGD…

非计算机专业考软考高项有必要吗?

我认为这非常重要。 看了你的介绍&#xff0c;如果你已经考取了会计证书&#xff0c;而且想要考取计算机专业的证书&#xff0c;或者你的职业规划涉及到计算机岗位&#xff0c;又或者你对计算机感兴趣&#xff0c;我建议你优先考虑软考&#xff0c;因为这个证书的含金量是有保…

冯喜运:4.22晚间欧市支撑阻力:现货黄金+美原油走势及操作建议

【黄金消息面解析 】&#xff1a;周一(4月20日)欧市早盘&#xff0c;现货黄金短线加速跳水&#xff0c;金价目前跌向2350美元/盎司关口&#xff0c;日内崩跌逾40美元。美国定于周五公布的个人消费支出(PCE)物价指数预计将显示&#xff0c;3月PCE物价指数同比增幅将从2月份的2.5…

Linux 安装 Docker +Docker Compose + cucker/get_command_4_run_container

TIP&#xff1a;下面演示的 Linux 系统为 CentOS 7.9。 Docker 更新你的系统并安装必要的依赖项&#xff1a; sudo yum update -y sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加 Docker 的官方仓库&#xff1a; sudo yum-config-manager --add-rep…

什么是 PCIe 及其工作原理?

什么是外围组件互连 Express (PCIe)&#xff1f; 外围组件互连 Express (PCIe) 是一种高速串行计算机扩展总线标准&#xff0c;可将设备连接到主板。 它于 2004 年首次推出&#xff0c;作为以前 PCI 和 AGP 方式的替代。 PCIe 允许处理器和各种扩展卡&#xff08;例如显卡、声…

上市公司数字化转型速度测-含代码及原始数据(2000-2022年)

数据来源&#xff1a;Wind数据库、企业年报时间跨度&#xff1a;2000-2022年 其中吴非、赵宸宇版本的数据是从2000到2022年&#xff1b;袁淳版本和李瑛玫版本的数据均是从2001-2022年。数据范围&#xff1a;上市公司数据指标&#xff1a;计算了三份测算数字化转型速度的数据。其…

关系抽取与属性补全

文章目录 实体关系抽取的任务定义机器学习框架属性补全 实体关系抽取的任务定义 从文本中抽取出两个或者多个实体之间的语义关系&#xff1b;从文本获取知识图谱三元组的主要技术手段&#xff0c;通常被用于知识图谱的补全。美丽的西湖坐落于浙江省的省会城市杭州的西南面。&am…

基于SSM+Jsp+Mysql的文物管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

可视化大屏可不是花架子,绝对有实用价值。

Hello&#xff0c;我是大千UI工场&#xff0c;不少老铁觉得可视化大屏就是花架子&#xff0c;是取悦领导的&#xff0c;那真是不懂可视化大屏的价值。欢迎友友们关注、评论&#xff0c;如果有订单可私信。 可视化大屏并不是花架子&#xff0c;而是一种实际有效的工具&#xff0…

实战|哈尔滨等保2.0 Linux主机测评过程之身份鉴别

一、身份鉴别 a)应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别信息具有复杂度要求并定期更换。 输入 more /etc/shadow,得知系统所有用户&#xff0c;此语句字段格式有九段。 第一字段&#xff1a;用户名&#xff08;也被称为登录名…

Webpack-

定义 静态模块&#xff1a;指的是编写代码过程中的html&#xff0c;css&#xff0c;js&#xff0c;图片等固定内容的文件 打包&#xff1a;把静态模块内容压缩、整合、翻译等&#xff08;前端工程化&#xff09; 1&#xff09;把less/sass转成css代码 2&#xff09;把ES6降级…

C语言本身不难,难得是应用场景很多

你学了C语言多半是要做项目的&#xff0c;这个过程中C语言是远远不够的&#xff0c;你把这部分难度加到C语言上&#xff0c;自然就难了在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区…

基于51单片机智能窗帘仿真设计( proteus仿真+程序+设计报告+讲解视频)

基于51单片机智能窗帘仿真设计( proteus仿真程序设计报告讲解视频&#xff09; 基于51单片机智能窗帘仿真设计 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真设计4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单资料下载链接&#xff1a; 仿真图proteus8.9及以上…

一线实战,一次底层超融合故障导致的Oracle异常恢复

背景概述 某客户数据由于底层超融合故障导致数据库产生有大量的坏块&#xff0c;最终导致数据库宕机&#xff0c;通过数据抢救&#xff0c;恢复了全部的数据。下面是详细的故障分析诊断过程&#xff0c;以及详细的解决方案描述&#xff1a; 故障现象 数据库宕机之后&#xff0c…

Shell和Linux权限

目录 shell Liunx权限 用户 sudo Linux的权限管理 文件访问者的分类 文件的属性 文件的权限 文件全权限值的表示方法 1.字符表示 2.八进制数值表示 用户符号 修改文件访问权限 修改文件拥有者 修改拥有者和所属组 修改所属组 文件目录的权限的含义 问题 粘滞…

【C++航海王:追寻罗杰的编程之路】C++11(中)

目录 C11(上) 1 -> STL中的一些变化 2 -> 右值引用和移动语义 2.1 -> 左值引用和右值引用 2.2 -> 左值引用与右值引用比较 2.3 -> 右值引用使用场景与意义 2.4 -> 右值引用引用左值及其更深入的使用场景分析 2.5 -> 完美转发 C11(上) 1 -> STL…