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

news2024/12/23 4:04:24

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习!

欢迎志同道合的朋友一起加油喔🦾🦾🦾
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心


目录

 

一、概念

二、实现一个二叉搜索树

2.1 成员变量

2.2 搜索树的查找

2.3 操作—插入

2.4 搜索树的删除(难点)

  替换法分析

2.5 检查插入 / 删除后是否还是一棵二叉搜索树-- 中序遍历

性能分析



 

一、概念

二叉搜索树又称二叉排序树
它或者是一棵空树,或者是具有以下性质的二叉树:
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树
ps:二叉搜索树的中序遍历一定是有序的(从小到大)

二、实现一个二叉搜索树

2.1 成员变量

public class BinarySearchTree {
    private TreeNode root; //存放根节点
 
    private static class TreeNode {
        private int val;
        private TreeNode left;
        private TreeNode right;
        private TreeNode(int val) {
            this.val = val;
        }
    }
}

这里跟我们的二叉树成员变量大同小异,主要是去实现插入,查找,删除的逻辑。

2.2 搜索树的查找

 代码如下:

public Node search(int key){
        TreeNode cur=root;
        while(cur!=null){
            if(cur.val<key){
                cur=cur.right;
            }else if(cur.val==key){
                return cur;
            }else{
                cur=cur.left;
            }
        }
        return null;//走到这里,说明上面while没找到,也就是没有这个数据
    }

2.3 操作—插入

1.如果树为空树,即根为null,就可以直接插入。

2.如果树非空树,应按照查找逻辑找到插入位置,插入新节点。

        通过查找的规则来寻找插入节点,每次插入的节点都为叶子节点! 

        注意相同的key是不可以插入的!

从根节点开始,根据查找的规则用cur进行节点遍历,同时用prev来存储遍历的前一个节点,直到cur == null时,此时prev已经遍历到叶子节点,再进行判断key与该叶子节点的大小关系来决定放在left还是right。

 代码如下:

public boolean insert(int key) {
    // 二叉搜索树没有节点的情况
    if (root == null) {
        root = new TreeNode(key);
        return true;
    }
    // 二叉搜索树不为空的情况 -> 找到该节点要插入的位置进行插入
    // 如果已经存在该节点了, 则不用插入 -> 二叉搜索树中不能出现重复值
    TreeNode parent = null; // 记录cur的父节点
    TreeNode cur = root;
    while (cur != null) {
        if (cur.val < key) {
            parent = cur;
            cur = cur.right;
        } else if (cur.val > key) {
            parent = cur;
            cur = cur.left;
        } else {
            return false; // 插入重复的节点
        }
    }
    // 走到这, cur为空了, key 需要插入到 parent 的左节点或右节点中
    TreeNode newNode = new TreeNode(key);
    if (parent.val < key) {
        parent.right = newNode;
    } else {
        parent.left = newNode;
    }
    return true;
}

2.4 搜索树的删除(难点)

解题思路:

1. cur.left == null

①cur 是 root ,则 root = cur.right

②cur 不是 root , cur 是 parent.left ,则 parent.left = cur.right

③cur 不是 root, cur 是 parent.right ,则 parent.right = cur.right

2. cur.right == null

①cur 是 root ,则 root = cur.left

②cur 不是 root , cur 是 parent.left ,则 parent.left = cur.left

③cur 不是 root , cur 是 parent.right ,则 parent.right = cur.left

 3. cur.left != null && cur.right != null(难点)

思路: 需要使用 替换法 进行删除,即在它的右子树中寻找中序遍历下的第一个结点 ( 关键码最小 ) ,用它的值填补到被删除节点中,再来处理该结点的删除问题

  替换法分析

当带删除元素key有左右孩子的时候,直接把key删除是不现实的,因为你根本不知到key下面的结构是什么,就算知道,调整起来也无从下手,所以我们需要借助替换法来实现,既可以选择key的左子树中的最大值进行替换,也可以选择key的右子树中最小值进行替换,因为这样才能保证二叉搜索树的结构不被破坏。

代码如下:

public boolean remove(int key) {
    TreeNode parent = null;
    TreeNode cur = root;
    while (cur != null) {
        if (cur.val < key) {
            parent = cur;
            cur = cur.right;
        } else if (cur.val > key) {
            parent = cur;
            cur = cur.left;
        } else {
            removeNode(parent, cur);
            return true;
        }
    }
    return false;
}
 
private void removeNode(TreeNode parent, TreeNode cur) {
    if (cur.left == null) {
        if (cur == root) {
            root = cur.right;
        } else if (cur == parent.left) {
            parent.left = cur.right;
        } else {
            parent.right = cur.right;
        }
    } 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;
        }
    } else {
        TreeNode target = cur.right;
        TreeNode targetParent = cur;
        while (target.left != null) {
            targetParent = target;
            target = target.left;
        }
        // 走到这, target就是要删除节点的右子树中最小的节点, 接下来进行覆盖
        cur.val = target.val;
        // 覆盖完成, 现在需要删除 target 节点
        // 如果 cur.right 没有左孩子的情况, 此时的target就是cur.right
        // 即直接将 cur.right 覆盖到 cur 位置, 也就是满足 target == targetParent.right 条件
        // 所以需要进行特殊处理.
        if (target == targetParent.right) {
            targetParent.right = target.right;
        } else {
            targetParent.left = target.right;
        }
    }
}

2.5 检查插入 / 删除后是否还是一棵二叉搜索树-- 中序遍历

下图中序遍历的结果为:0,1,2,3,4,5,6,7,8,9

 代码如下:

    public List<Integer> inOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) {
            return list;
        }
        List<Integer> left = inOrder(root.left);
        list.addAll(left);//左
        list.add(root.key);//中
        List<Integer> right = inOrder(root.right);
        list.addAll(right);//右
        return list;
    }

咱们在对二叉搜索树进行CURD操作时,就可以通过调用中序遍历的调试和打印来判断是否正确!


性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能!

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:O(log2^N)

最差情况下,二叉搜索树退化为单支树,其平均比较次数为:O(N)

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

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

相关文章

怎么将webm格式转换成mp4,3招轻松学

怎么将webm格式转换成mp4&#xff1f;相对于已经广为人知的MP4&#xff0c;还有许多人对于WebM这种视频格式不太熟悉。WebM是一种免费开源的媒体文件格式。虽然Web.目前应用范围越来越广泛&#xff0c;但大家还是更习惯使用MP4&#xff0c;因为mp4是目前最为流行的视频文件格式…

【MySQL】MES中,发货计划取数逻辑

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

TryHackMe-CMSpit(boot2root)

CMSpit 你已确定 Web 服务器上安装的 CMS 存在多个漏洞&#xff0c;允许攻击者枚举用户并更改帐户密码。 您的任务是利用这些漏洞并破坏 Web 服务器。 端口扫扫描 循例nmap Web枚举 进80 很明显&#xff0c;cms就是Cockpit, 版本通过查看源代码的js版本可以得知是0.11.1 se…

FPGA/Verilog HDL/AC620零基础入门学习——第一个项目按键控制LED

介绍 最近要考试了&#xff0c;所以我赶紧补习FPGA&#xff0c;我们用的是小梅哥的AC620开发板&#xff0c;软件是Quartus。推荐看这个视频教程&#xff1a;零基础轻松学习FPGA&#xff0c;小梅哥FPGA设计思想与验证方法视频教程 设计步骤 设计定义 用按键控制LED灯的亮灭就…

YOLOv7如何提高目标检测的速度和精度,基于优化算法提高目标检测速度

目录 一、学习率调度二、权重衰减和正则化三、梯度累积和分布式训练1、梯度累积2、分布式训练 四、自适应梯度裁剪 大家好&#xff0c;我是哪吒。 上一篇介绍了YOLOv7如何提高目标检测的速度和精度&#xff0c;基于模型结构提高目标检测速度&#xff0c;本篇介绍一下基于优化算…

xcode历史版本下载

一、背景 较早之前做过一个项目&#xff0c;当时使用swift 3.x开发。 项目结束后就没再有新需求与更新。 但最近呢需要对项目的某些功能进行调整&#xff0c;项目又重新被拾了起来。 我们知道现在的swift 版本已经到了 5.x&#xff0c; 相应的语法上较 3.x版本也有了不小的变化…

从2-3-4树到红黑树原理分析以及C++实现红黑树建树

总结规律&#xff1a; 1、2-3-4树&#xff1a;新增元素2节点合并&#xff08;节点中只有1个元素&#xff09;3节点&#xff08;节点中有2个元素&#xff09; 红黑树&#xff1a;新增一个红色节点黑色父亲节点上黑下红&#xff08;2节点---------------不要调整&#…

上班族如何安排时间提高工作效率?

对于上班族来说&#xff0c;合理安排时间可以兼顾生活和工作&#xff0c;不仅能够减少加班次数&#xff0c;还可以提高工作效率&#xff0c;减少工作中的负面情绪。但是有不少小伙伴表示&#xff0c;自己不知道如何安排时间从而提高工作效率&#xff0c;这应该怎么办呢&#xf…

张勇:阿里云是一家云计算产品公司,要坚定走向“产品被集成”

4月26日&#xff0c;在2023阿里云合作伙伴大会上&#xff0c;阿里巴巴董事会主席兼CEO、阿里云智能CEO张勇表示&#xff0c;阿里云的核心定位是一家云计算产品公司&#xff0c;生态是阿里云的根基。让被集成说到做到的核心&#xff0c;是要坚定走向“产品被集成”。 张勇表示&a…

小米13 Ultra:携光前行,追求每一束光的精确还原

“光&#xff0c;是影像的原点”&#xff0c;一切色彩、影调都在于光。我们目之所及的大千世界&#xff0c;皆被光与影一笔一划细细勾勒&#xff0c;为“视”界晕染上或鲜明、或复古、或反差、或梦幻的色调。我们用“光”去描绘、定义“影像”&#xff0c;让一切平凡的事物&…

Notion AI 胜于 ChatGPT ?

去年&#xff08;2022年&#xff09;12 月初&#xff0c;在社区中 OpenAI 的 ChatGPT 刚出来就火了一把&#xff0c;当时一度因为访问量太大导致崩溃宕机&#xff1b;最近&#xff08;2023 年1 月底&#xff09; ChatGPT 又火了&#xff0c;资本市场新增 ChatGPT 概念&#xff…

入局生成式AI,看好亚马逊(AMZN)中期表现

来源; 猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;由于近期亚马逊&#xff08;AMZN&#xff09;宣布发布多项生成式AI以及AIGC相关产品&#xff0c;入局全球大模型竞赛当中。中信证券发布研报看好入局生成式AI。中信证券在研报中称&#xff0c;亚马逊作为北美…

【Git】拉取代码/提交代码

1.从将本地代码放入远程仓库 (如果有分支的情况) [git checkout xx切换分支后 git add . 将本地所有改动文件新增 commit之后 git push(将代码全部提交)] 分支操作 #查看分支 git branch #创建分支 git branch test #切换分支 git checkout test #修改代码 #提交代码git ad…

DPDK和RDMA的区别

网络的发展好像在各方面都是滞后于计算和存储&#xff0c;时延方面也不例外&#xff0c;网络传输时延高&#xff0c;逐渐成为了数据中心高性能的瓶颈。因为传统两个节点间传输数据的网络路径上有大量的内存拷贝&#xff0c;导致网络传输效率低下&#xff0c;网络数据包的收发处…

MySQL——索引

目录 一、索引 1.1 索引的概念 1.2 索引的运用 1.2.1 索引的创建 1.2.2 查看表的索引 ​1.2.3 创建索引 1.2.4 删除索引 1.2.5 总结 二、索引底层的数据结构 B 树的特点 一、索引 1.1 索引的概念 当我们是使用查询语句对表中的数据进行条件查询的时候&#xff0c;M…

Python小姿势 - Python爬取数据的库——Scrapy

Python爬取数据的库——Scrapy 一、爬虫的基本原理 爬虫的基本原理就是模拟人的行为&#xff0c;使用指定的工具和方法访问网站&#xff0c;然后把网站上的内容抓取到本地来。 爬虫的基本步骤&#xff1a; 1、获取URL地址&#xff1a; 2、发送请求获取网页源码&#xff1b; 3、…

NAT网络地址转换

1.前言 随着网络设备的数量不断增长&#xff0c;对IPv4地址的需求也不断增加&#xff0c;导致可用IPv4地址空间逐渐耗尽。解决IPv4地址枯竭问题的权宜之计是分配可重复使用的各类私网地址段给企业内部或家庭使用。但是&#xff0c;私有地址不能在公网中路由&#xff0c;即私网…

数据结构,Map和Set的使用方法

在数据结构中我们经常会使用到 Map 和 Set &#xff0c;Map 和 Set 到底是什么&#xff0c;它怎样去使用呢&#xff1f;因此博主整理出 Map 和 Set 这两个接口的介绍与使用方法。 目录 1. 啥是Map和Set? 1.1 Map和Set的模型 2. Map的使用 2.1Map的说明 2.2 Java中Map常用…

【C++】列表初始化声明范围forSTL容器新变化

文章目录 什么是C11列表初始化**C98中{}的初始化**内置类型的列表初始化 关于initializer_list使用场景: 声明auto-变量类型推导decltype类型推导nullptr 范围forSTL的新变化新容器:容器中的一些新方法 什么是C11 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1),使得C…

Java 输出机制 数据类型

目录 一、输出机制 1.print和println的差别 2.可接收不同类型参数 3.输出函数中 符号的使用 二、Java 数据类型 1.整型类型 2.浮点类型 3.字符类型 三、基本数据类型转换 1.自动类型转换 2.强制类型转换 3.练习题 四、基本数据类型和String类型的转换 1.基本类…