【数据结构】二叉搜索树

news2024/12/26 10:46:06

一、概念

二叉搜索树也叫二叉排序树。在一颗二叉搜索树中,他的左子树二点节点值一定比根节点的值小,他的右子树节点的值一定比根节点的值大。

二、特点

  1. 他的左子树节点的值一定比根节点的值小

  1. 他的右子树节点的值一定比根节点的值大

  1. 他的每一颗子树都是一颗二叉搜索树

  1. 他的查找效率很高,类似二分查找O(logn)

三、代码实现

    • 准备字段

需要准备的有二叉树的节点类跟根节点

public class BinaryTree {
    static class TreeNode {
        public int val;      //节点的值
        public TreeNode left;//左孩子地址
        public TreeNode right;//右孩子地址

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root;   //根节点
}

2.查找

二叉搜索树里的查找很简单,我们拿要查找的值鱼根节点进行比较,如果比根节点大就去根节点的右子树查找,如果比根节点小就去根节点的左边查找,如果相等就返回根节点。

public class BinaryTree {
    static class TreeNode {
        public int val;      //节点的值
        public TreeNode left;//左孩子地址
        public TreeNode right;//右孩子地址

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root;   //根节点

    /**
     * 查找返回找到的节点
     * @param key
     * @return
     */
    public TreeNode search(int key){
        //定义一个节点代替根节点去遍历查找
        TreeNode cur = root;
        
        //循环查找
        while (cur != null) {
            if (cur.val < key) {
                //如果key的值比根节点的值大就去右子树查找
                cur = cur.right;
            } else if (cur.val > key) {
                //如果key的值比根节点的值大就去左子树查找
                cur = cur.left;
            } else {
                //说明找到了,就返回节点
                return cur;
            }
        }
        
        //没找到返回空
        return null;
    }
}
    • 插入

我们先构造一颗二叉搜索树,然后在这棵树里分别插入元素8,9,0

插入8:比3大在右子树找合适的位置,比4的往右,比5大往右插入到5的右边

9跟0类似,我们发现每次插入的元素都会到叶子节点,于是我们只需要找到合适的叶子节点,然后再判断插入叶子节点的左边还是右边

public void insert(int val){
        //创建节点
        TreeNode node = new TreeNode(val);
        
        //创建节点代替跟节点遍历找到合适位置,并记录父亲节点的位置
        TreeNode parent = null;
        TreeNode cur = root;
        
        //遍历
        while (cur != null){
            if(cur.val < val){
                //去右子树
                parent = cur;
                cur = cur.right;
            }else  if(cur.val > val){
                //去左子树
                parent = cur;
                cur = cur.left;
            }else {
                //说明已经存在值了,直接返回
                return;
            }
        }
        
        //此时cur = null parent指向的位置就是要插入的叶子节点
        if(parent.val < val) {
            //说明比该叶子节点值大,插入右边
            parent.right = node;
        }else {
            //插入左边
            parent.left = node;
        }
    }
    • 删除

删除操作就需要进行分类:如果要删除的节点没有左孩子;如果要删除的节点没有右孩子;如果要删除的节点有左右孩子

    • 待删节点没有左孩子

当我们找到这个节点后发现他没有左孩子,此时我们有需要进行讨论:这个节点是不是根节点;这个节点是他父亲节点的左孩子;这个节点是他父亲节点的右孩子。

    • 跟节点

他是跟节点时,由于没有左孩子,所以直接让跟节点的右孩子指向跟节点的右孩子

    • 是父亲的左孩子

他是父亲节点的左孩子且他没有左孩子,所以此时直接让父亲节点的左孩子指向这个节点的右孩子

    • 是父亲的右孩子

他是父亲节点的右孩子且他没有左孩子,所以此时直接让父亲节点的右孩子指向这个节点的右孩子

    • 待删节点没有右孩子

当我们找到这个节点后发现他没有右孩子,此时我们有需要进行讨论:这个节点是不是根节点;这个节点是他父亲节点的左孩子;这个节点是他父亲节点的右孩子。

    • 跟节点

是根节点且没有右孩子,说明只有左孩子,删除根节点只需要将根节点指向根节点的左孩子

    • 是父亲的左孩子

由于待删节点没有右孩子,所以直接让他的父亲的左边指向待删节点的左孩子

    • 是父亲的右孩子

由于待删节点没有右孩子,所以直接让父亲的右边指向待删节点的左孩子

    • 待删节点有左右孩子

当既有左孩子又有右孩子时,我们此时使用替换删除,也就是在待删节点的左子树去找最大值(左子树的最右边)或者右子树的最小值(右子树的最左边)找到后,与待删节点的值进行交换后删除找到的该节点

public void remove(int key){
        //先找到该节点与其父亲节点
        TreeNode cur = root;
        TreeNode parent = null;

        while (cur != null){
            if(cur.val < key){
                parent = cur;
                cur = cur.right;
            }else if(cur.val > key){
                parent = cur;
                cur = cur.left;
            }else {
                //找到进行删除
                delete(parent,cur);
                return;
            }
        }
    }

    private void delete(TreeNode parent, TreeNode cur) {
        if(cur.left == null){
            //没有左子树
            if(cur == root){
                //如果是跟节点
                root = root.right;
            }else if(cur == parent.left){
                //是父亲的左子树
                parent.left = cur.right;
            }else {
                //是父亲的右子树
                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.right;
            }
        }else {
            //此时既有左又有右:去右边找最小值,也就是右子树的最左边
            TreeNode target = cur.right;
            TreeNode targetParent = cur;

            while (target.left != null){
                targetParent = target;
                target = target.left;
            }

            //找到了交换值
            cur.val = target.val;

            //删除target:处理特殊情况下面说明
            if(target == targetParent.left){
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }

特殊情况:当去右子树里找最小值时,每一个子树没有左子树的时候,此时待删节点的右边第一个就是最小值,这种情况删除时需要注意

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

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

相关文章

java+springboot笔记2023002

java的注解机制&#xff1a; Java主要提供了5个基础注解&#xff0c;分别是&#xff1a; Override Deprecated SuppressWarnings SafeVarargs FunctionalInterface Java元注解&#xff1a; Retention&#xff0c; Target&#xff0c; Inherited&#xff0c; Documented&#x…

算法刷题打卡第66天:极大极小游戏

极大极小游戏 难度&#xff1a;简单 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &a…

MySQL索引命中与失效

目录创建表MySQL执行优化器索引的命中与失效情况总结讨论MySQL索引命中与失效&#xff0c;我们得先来创建表 创建表 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABL…

java动态规划算法

使用场景 动态规划最重要的是转移方程&#xff0c;而转移方程需要递归和记忆化搜索产生的表&#xff0c;因此直接贴出转移方程是没什么用的&#xff0c;不探究如何从递归到记忆化搜索再到转移方程&#xff0c;还是很难想到怎么去得到转移方程。下面我们将从例子中探寻如何三步走…

四、Gradle项目的生命周期

文章目录四、Gradle项目的生命周期【尚硅谷】Gradle教程-讲师&#xff1a;刘辉 生活明朗&#xff0c;万物可爱&#xff0c;人间值得&#xff0c;未来可期 四、Gradle项目的生命周期 Gradle 项目的生命周期分为三大阶段&#xff1a;Initialization -> Configuration -> E…

Maestro 薛定谔软件简单分子对接案例

##参考&#xff1a; Maestro 薛定谔软件使用&#xff1a; https://www.bilibili.com/video/BV1RN411X7Te https://www.youtube.com/watch?vNkM8jjHr7f4&listPL3dxdlKx_PcfuvHwJ0RjpZFt4HjwyTr7f Maestro 薛定谔对接&#xff1a; https://www.bilibili.com/video/BV17p…

【Java多线程】线程的常用方法

测试Thread中的常用方法1.start():启动当前线程&#xff1b;调用当前线程的run()2.run():通常需要重写Thread类中的此方法&#xff0c;将创建的线程要执行的3.currentThread():静态方法&#xff0c;返回当前代码的线程4.getName():获取当前线程的名字5.setName():设置当前线程的…

MySQL逻辑删除+Mybatis-Plus = 墙裂推荐

目录前言逻辑删除使用Mybatis-Plus逻辑删除它做了什么注意写在后面的一些话前言 一般情况下&#xff0c;我们要删除一条数据&#xff0c;直接使用 delete 即可&#xff0c;就像这样&#xff1a;delete from user where id 1&#xff0c;这样做的好处是&#xff1a; 符合我们…

C进阶_字符串库函数

目录 求字符串长度 strlen 常规实现 递归实现 指针-指针实现 长度不受限制的字符串函数 strcpy 模拟实现strcpy strcat 模拟实现strcat strcmp 模拟实现strcmp 长度受限制的字符串函数 strncpy strncat strncmp 求字符串长度 strlen size_t strlen ( const c…

前端工具(运用造型)

CSS预处理器的使用方法 1、什么是css预处理器 CSS预处理器是一种专门的编程语言&#xff0c;用来为CSS增加一些编程特性&#xff08;CSS本身不是编程语言&#xff09;不需要考虑浏览器兼容问题&#xff0c;因为CSS预处理器最终编译和输出的仍是标准的CSS样式。可以在CSS预处理…

磨金石教育摄影技能干货分享|简述特效在影视制作中的四大作用

近三年因为疫情的原因&#xff0c;极少去影院去看电影。 想起来上次看电影还是去年八月份&#xff0c;当时上映的是科幻大作《沙丘》。看科幻电影&#xff0c;最大的期待就是导演编剧们对外星球与外太空场景的塑造。那些逼真的场景与炫酷的战舰航天器&#xff0c;满足了我对未知…

设计模式_结构型模式 -《适配器模式》

设计模式_结构型模式 -《适配器模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 如果去欧洲国家去旅游的话&#xff0c;他们的插座如下图最左边&#xff0c;是欧洲标准。而我们使用的插头如下图…

Kindle 可旋转桌面时钟

前言 自己的 Kindle 吃灰很久了&#xff0c;想做个时钟用&#xff0c;但是网上可选的时钟网站比较少&#xff0c;这些时钟网站里面&#xff0c;要么太简单 界面也比较丑陋&#xff0c;要么内容太多 有些本末倒置了&#xff0c;要么网址特别长 输入网址的时候太麻烦。 干脆自己…

【ROS】—— 机器人导航(仿真)—导航原理(十七)

文章目录前言1. 导航模块简介1.1 全局地图1.2 自身定位1.3 路径规划1.4 运动控制1.5 环境感知2. 导航之坐标系前言 &#x1f4e2;本系列将依托赵虚左老师的ROS课程&#xff0c;写下自己的一些心得与笔记。 &#x1f4e2;课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ …

Min_25筛详解

概述 Min_25是日本一个ACM选手的ID&#xff0c;这个筛法是他发明的&#xff0c;所以称之为Min_25筛。它能在亚线性复杂度求出一类积性函数的 fff 的前缀和&#xff0c;前提 是这个积性函数在质数和质数的幂位置的函数值比较好求。借助埃拉托色尼筛的思想 将原问题转化成与质因…

Allegro如何导出和导入设计规则操作指导

Allegro如何导出和导入设计规则操作指导 当需要借用另外一款PCB的设计规则时候,Allegro支持把PCB设计规则导入到另外一块PCB中,如下图 具体操作如下 打开规则管理器打开后如下图

2023.1.15 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.本文贡献5.PROPOSED METHOD5.1 Problem Formulation5.2 Personalized Time Intervals5.3 Embedding Layer5.4 Time Interval-Aware Self-Attention5.4.1 Time Interval-Aware Self-attention Layer5.4.2 Causality5.4.3 Point-Wise Fe…

QT可直接安装的离线版最后版本5.14.2

以前用c#来做组态&#xff0c;自定义控件开发起来也还过得去&#xff0c;但QT的控件和graphics view貌似更有优势&#xff0c;个人观点吧&#xff01;工控领域的组态用上QT还是不错的选择。 从2000前开始使用qt&#xff0c;算起来也有20多年了。个人感觉用起来最顺手的应该时Q…

【PHP】一文详解如何连接Mysql数据库(附源码)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

24考研——专业院校选报指南(3步决定专业选择、11大类本科对应考研专业简析、6步决定目标院校)

文章目录一、专业选择指导1.1 考研整体形势1.2 考研专业选报1.2.1 专业设置1.2.2 专硕专业设置1.2.3 专业代码含义1.2.4 区分“学硕和专硕”1.2.5 专业选择步骤&#xff08;跨专业考研难度&#xff09;1.2.6 跨专业考研简析&#xff08;法硕/教育/会计、审计、图书情报/思想政治…