Java中的二叉搜索树(如果想知道Java中有关二叉搜索树的知识点,那么只看这一篇就足够了!)

news2025/2/27 18:10:40

        前言:Java 提供了丰富的数据结构来处理和管理数据,其中 TreeSet 和 TreeMap 是基于红黑树实现的集合和映射接口。它们有序地存储数据,提供高效的搜索、插入和删除操作。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

先让我们看一下本文大致的讲解内容:

目录

1.二叉搜索树的认识

        (1)二叉搜索树的概念

        (2)二叉搜索树的性质

2.有关二叉搜索树的常用操作

        【1】插入操作

        【2】查找操作

        【3】删除操作

1.cur.left == null

2.cur.right == null

3.cur.left != null && cur.right != null

3.二叉树的应用场景

1. 数据结构和算法

2. 数据库和文件系统

3. 图形和游戏开发


1.二叉搜索树的认识

        (1)二叉搜索树的概念

        在开始学习TreeSet与TreeMap之前,我们需要先学习一下Java中的二叉搜索树,二叉搜索树是一种特殊的二叉树,其中每个节点都有一个值,并满足以下性质:

  • 对于每个节点,左子树所有节点的值都小于该节点的值。

  • 对于每个节点,右子树所有节点的值都大于该节点的值。

如图:

从上图中我们可以很明显的观察出二叉搜索树的上述两个特性。

        (2)二叉搜索树的性质

        在了解完了二叉搜索树的概念之后,我们需要学习一下有关二叉搜索树的性质,对于一棵二叉搜索树而言,其都有以下三个性质:

  • 有序性:二叉搜索树的中序遍历结果是一个递增的有序序列。

  • 动态性:二叉搜索树支持动态插入和删除操作,适用于需要频繁更新的数据集合。

  • 查找效率:在理想情况下,二叉搜索树的查找、插入和删除操作的时间复杂度为 O(log n)。

        ——这里读者可能会对其中的一些性质不是很理解,没有关系,继续向下进行阅读即可,在后续的文本中,我们会慢慢的理解其中的意思。

2.有关二叉搜索树的常用操作

        【1】插入操作

        插入操作用于向二叉搜索树中插入新值。插入过程从根节点开始,根据当前节点的值与新值的比较结果,决定将新值插入到左子树还是右子树。

以下是实现该操作的代码:

public void insertNode(int key) {
    // 如果根节点为空,直接插入新节点作为根节点
    if (root == null) {
        root = new TreeNode(key);
        return;
    }

    // 初始化当前节点为根节点,父节点为null
    TreeNode cur = root;
    TreeNode parent = null;
    TreeNode node = new TreeNode(key);

    // 寻找合适的位置插入节点
    while (cur != null) {
        if (cur.val < key) { // 当前值小于插入值,向右子树移动
            parent = cur;
            cur = cur.right;
        } else if (cur.val > key) { // 当前值大于插入值,向左子树移动
            parent = cur;
            cur = cur.left;
        } else { // 当前值等于插入值,直接返回,不插入重复值
            return;
        }
    }

    // 根据父节点值与插入值的比较结果,插入新节点到左子树或右子树
    if (parent.val > key) {
        parent.left = node;
    } else {
        parent.right = node;
    }
}

读者可以跟着下面的解释来对上边的代码进行理解:

  1. 根节点为空检查

    • 如果 root 为空,直接将新节点 TreeNode(key) 作为根节点插入,并返回。
  2. 初始化当前节点和父节点

    • cur 用于遍历树,从 root 开始。
    • parent 用于记录 cur 的父节点。
  3. 寻找合适的插入位置

    • cur 不为空时,比较 cur.valkey
      • 如果 cur.val 小于 key,移动到右子树。
      • 如果 cur.val 大于 key,移动到左子树。
      • 如果 cur.val 等于 key,直接返回,不插入重复值。
  4. 插入新节点

    • 根据 parent.valkey 的比较结果,将新节点插入到 parent 的左子树或右子树。

        ——这样我们就学会了插入操作了!

        【2】查找操作

        查找操作用于在二叉搜索树中查找特定值。查找过程从根节点开始,根据当前节点的值与目标值的比较结果,决定在左子树还是右子树继续查找。

以下是实现该操作的代码:

public TreeNode search(int key) {
    // 初始化当前节点为根节点
    TreeNode cur = root;
    
    // 遍历树,直到找到目标节点或遍历到空节点
    while (cur != null) {
        if (cur.val < key) { // 当前节点值小于目标值,移动到右子树
            cur = cur.right;
        } else if (cur.val > key) { // 当前节点值大于目标值,移动到左子树
            cur = cur.left;  // 这里应修正为cur = cur.left;
        } else { // 找到目标节点
            return cur;
        }
    }
    // 如果没有找到目标节点,返回 null
    return null;
}

读者可以跟着下面的解释来对上边的代码进行理解:

  1. 初始化当前节点

    • cur 用于遍历树,从 root 开始。
  2. 遍历树

    • cur 不为空时,比较 cur.valkey
      • 如果 cur.val 小于 key,移动到右子树 (cur = cur.right)。
      • 如果 cur.val 大于 key,移动到左子树 (cur = cur.left)。
      • 如果 cur.val 等于 key,返回当前节点。
  3. 返回结果

    • 如果遍历完整棵树没有找到目标节点,返回 null

        【3】删除操作

        删除操作用于从二叉搜索树中删除指定值。删除节点分为三种情况:叶子节点、只有一个子节点的节点和有两个子节点的节点。

        由于删除操作比较哦啊复杂,所以我们这里重点讲解一下,对于删除操作,我们可能会有以下的可能情况:

——现在我们假设待删除结点为 cur, 待删除结点的双亲结点为 parent:

1.cur.left == null

        1. cur 是 root,则 root = cur.right
        2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
        3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right

2.cur.right == null

        1. cur 是 root,则 root = cur.left
        2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left

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

3.cur.left != null && cur.right != null

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

我们大致了解了删除的三种可能的大情况之后,现在让我们尝试着编写一下代码:

public void remove(int key) {
    TreeNode parent = null; // 父节点初始化为 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; // 删除节点后退出方法
        }
    }
}

private void removeNode(TreeNode parent, TreeNode cur) {
    if (cur.right == null) { // 当前节点没有右子树
        if (cur == root) { // 当前节点是根节点
            root = root.left; // 根节点指向左子树
        } else if (parent.left == cur) { // 当前节点是父节点的左子节点
            parent.left = cur.left; // 父节点左子节点指向当前节点的左子树
        } else { // 当前节点是父节点的右子节点
            parent.right = cur.left; // 父节点右子节点指向当前节点的左子树
        }
    } else if (cur.left == null) { // 当前节点没有左子树
        if (cur == root) { // 当前节点是根节点
            root = root.right; // 根节点指向右子树
        } else if (parent.left == cur) { // 当前节点是父节点的左子节点
            parent.left = cur.right; // 父节点左子节点指向当前节点的右子树
        } else { // 当前节点是父节点的右子节点
            parent.right = cur.right; // 父节点右子节点指向当前节点的右子树
        }
    } else { // 当前节点有两个子节点
        TreeNode targetParent = cur; // 目标节点的父节点初始化为当前节点
        TreeNode target = cur.right; // 目标节点初始化为当前节点的右子节点
        // 寻找右子树中的最左节点
        while (target.left != null) {
            targetParent = target;
            target = target.left;
        }
        cur.val = target.val; // 用右子树中最左节点的值替换当前节点的值
        // 调整指针以删除目标节点
        if (targetParent.left == target) {
            targetParent.left = target.right;
        } else {
            targetParent.right = target.right;
        }
    }
}

——这里我们给每一条代码都加上了注释,读者可以根据注释来对上述代码进行理解!!!

这样我们就了解了二叉搜索树中常用的操作了.

3.二叉树的应用场景

        学习完二叉树的概念以及其基本的使用之后,让我们来学习一些二叉树的应用场景,二叉树(Binary Tree)在日常中有着广泛的应用。以下是一些主要的实际应用场景:

1. 数据结构和算法

  • 二叉搜索树(BST):用于实现高效的搜索、插入和删除操作,时间复杂度平均为 O(log n)。

  • 平衡树(如AVL树、红黑树):这些是自平衡二叉搜索树,确保树的高度保持在 O(log n),从而提供高效的操作。

  • 堆(Heap):二叉堆用于实现优先队列。最大堆用于实现高效的最大值查找,最小堆用于最小值查找。

2. 数据库和文件系统

  • B树和B+树:这些是多路搜索树,常用于数据库索引和文件系统索引,以提高查询和检索的效率。

  • Trie树:一种多叉树,用于实现前缀匹配,常用于字典存储和自动补全功能。

3. 图形和游戏开发

  • 四叉树和八叉树:用于空间分割,以提高碰撞检测、渲染和其他空间查询操作的效率。

  • 场景图(Scene Graph):在3D图形引擎中,场景图是一个树状结构,用于管理和渲染场景中的对象。

这样我们就大致的了解了二叉树在今后的日常中有哪些用武之地了!!!


以上就是本篇文章的主要内容了!!!

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

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

相关文章

web期末大作业家乡-周口

代码下载: https://pan.quark.cn/s/64c61dfc0928

【学术大咖云集】第二届网络、通信与智能计算国际会议(NCIC 2024)

第二届网络、通信与智能计算国际会议 The 2nd International Conference on Networks, Communications and Intelligent Computing&#xff08;NCIC 2024&#xff09; 2024年11月22日-25日 中国 | 北京 www.icncic.org 第二届网络、通信与智能计算国际会议&#xff08;NCIC…

新书速览|动手学PyTorch建模与应用:从深度学习到大模型

《动手学PyTorch建模与应用&#xff1a;从深度学习到大模型》 本书内容 《动手学PyTorch建模与应用:从深度学习到大模型》是一本从零基础上手深度学习和大模型的PyTorch实战指南。《动手学PyTorch建模与应用:从深度学习到大模型》共11章&#xff0c;第1章主要介绍深度学习的概念…

proto 同级文件引入问题小记

文章目录 1. 写在最前面2. 关于报错2.1 增加字段前2.2 增加字段后 3. 临时解决办法3.1 合并3.2 写入绝对路径 4. 原因5.碎碎念6. 参考资料 1. 写在最前面 笔者昨天遇到一个十分奇怪的事情&#xff0c;「在同一级目录的 proto 文件&#xff0c;引用的时候&#xff0c;报找不到的…

数据中台建设之数据采集

目录 一、数据采集 1.1 概述 1.2 线上行为采集 1.2.1 概述 1.2.2 客户端埋点 1.2.2.1 埋点方式分类 1.2.2.2 优略势分析 1.2.2.3 埋点举例 1.2.3 服务端埋点 1.3 线下行为采集 1.3.1 概述 1.3.2 网络信号采集 1.3.3 图像识别采集 1.3.4 设备日志采集 1.4 互联网数…

演播室级字幕技术,性能卓越,满足多场景需求

如何在浩如烟海的视频内容中脱颖而出&#xff0c;成为每个企业亟需解决的关键问题。美摄科技&#xff0c;作为视频编辑处理技术的领航者&#xff0c;携其革命性的视频编辑处理SDK&#xff0c;特别是行业领先的字幕模块&#xff0c;为企业视频创作带来了前所未有的变革与升级。 …

springboot多媒体内容管理系统-计算机毕业设计源码08580

摘 要 随着人类向信息社会的不断迈进&#xff0c;风起云涌的信息时代正掀起一次新的革命&#xff0c;同时计算机网络技术高速发展&#xff0c;网络管理运用也变得越来越广泛。因此&#xff0c;建立一个多媒体内容管理系统&#xff08;CMS&#xff09;的设计与优化来管理多媒体内…

第三周:网络应用(上)

一、网络应用&#xff08;层&#xff09;内容概述 我们已经知道&#xff0c;Internet的体系结构是符合TCP/IP协议栈的&#xff0c;而“应用层”就在这个协议的最上层。 本讲内容包括&#xff1a; 二、网络应用的基本原理 常见网络应用包括&#xff1a; 问&#xff1a;网络应…

Redis 缓存中间件

目录 概念 安装redis redis基本命令 给redis添加密码 基础数据类型 string类型 list列表类型 set创建&#xff08;一个键对应一个值&#xff09; set 创建数据 get 获取数据 keys * 展示所有的键 exists 判断键值是否存在 type 查看数据的类型 del 删除键 rename…

期刊评价指标及其查询方法

1、期刊评价体系一 科睿唯安《期刊引证报告》&#xff08;Journal Citation Reports, JCR&#xff09; 科睿唯安每年发布的《期刊引证报告》&#xff08;Journal Citation Reports, JCR&#xff09;是一个独特的多学科期刊评价工具。JCR数据库提供基于引文数据的统计信息的期…

数字信号||快速傅里叶变换(FFT)(4)

实验四 快速傅里叶变换(FFT) 一、实验目的 (1)加深对快速傅里叶变换(FFT)基本理论的理解。 (2)了解使用快速傅里叶变换(FFT)计算有限长序列和无限长序列信号频谱的方法。 (3)掌握用MATLAB语言进行快速傅里叶变换时常用的子函数。 二、实验涉及的MATLAB子函数 1.fft 功能&am…

鸟哥的Linux私房菜(三)之环境开发工具篇

文章目录 Linux软件包管理器 - yumLinux下安装软件的方式认识yum查找软件包安装软件如何实现本地机器和云服务器之间的文件互传及其云服务器之间互传卸载软件 Linux编辑器 - vimvim的基本概念vim下各模式的切换vim命令模式各命令汇总vim底行模式各命令汇总vim替换模式各命令汇总…

快速幂的求解方法(位运算)

需要求解幂运算的解法&#xff0c;可以将需要运算的内容进行判别&#xff0c;众所周知&#xff0c;幂就是指数&#xff0c;就是将底数乘以自身完成n次自相乘&#xff0c;那么就可以幻化为他的幂的简化计算&#xff1b; 以二进制为例&#xff0c;你要求&#xff0c;即可以看作是…

win10系统通过docker部署pytorch的GPU环境

命名实体有关文章参考这篇文章 中文地址命名实体识别训练和预测 win10系统安装cuda环境参考这篇文章 搭建Pytorch的GPU环境超详细 文件结构 准备环境 (1)、安装cuda环境 (2)、安装docker 1、创建基础镜像,安装pytorch和python dockerfile # 使用适当的基础镜像 FROM…

安全防护软件的必要性:从微软蓝屏事件谈起

最近微软遭遇了的大规模蓝屏事件&#xff0c;让全球很多用户措手不及。这次事件告诉我们&#xff0c;保护我们的电脑和数据&#xff0c;安全防护软件是多么重要。 微软蓝屏事件源于网络安全公司CrowdStrike的技术更新错误&#xff0c;导致全球范围内大量Windows用户系统崩溃&a…

一元二次方程编程求解过程+题目

输入 输入的第一行包含两个正整数 T,M&#xff0c;分别表示方程数和系数的绝对值上限。 接下来 T 行&#xff0c;每行包含三个整数 a,b,c。 输出 输出 T 行&#xff0c;每行包含一个字符串&#xff0c;表示对应询问的答案&#xff0c;格式如题面所述。 每行输出的字符串中…

【netty系列-06】深入理解select、poll和epoll多路复用的区别

Netty系列整体栏目 内容链接地址【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478【三】深入理解NIO的基本原理和底层…

分布式架构网络通信(RPC,RMI) 03

文章目录 1. 基本原理2. RPC 远程过程调用3. RMI 远程方法调用4. RMI代码实现4. BIO、NIO、AIO4.1 同步和异步4.2 阻塞和非阻塞4.3 BIO4.4 NIO4.5 AIO 1. 基本原理 要实现网络机器间的通讯&#xff0c;首先得来看看计算机系统网络通信的基本原理&#xff0c;在底层层面去看&am…

WSL桥接网络配置

仅做记录与分享&#xff0c;平台版本等不同无法指导更多。 一、需求 ubuntu虚拟机&#xff08;WSL&#xff09;桥接win11并且能联通外网&#xff08;百度之类&#xff09; 二、环境&#xff1a; 版本 Windows 11 专业版 版本号 23H2 安装日期 ‎2024/‎6/‎20 操作系统版本…

Mysql 集群搭建 05

文章目录 1. Mysql主从复制集群搭建1.1 主库配置1.2 从库配置 2. 分库分表2.1 拆分策略2.2 实现技术2.2.1 MyCat概述2.2.2 MyCat入门2.2.3 配置 schema.xml 3. 双主双从4. 双主双从读写分离 1. Mysql主从复制集群搭建 主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志…