java数据结构_Map和Set_9.1
1. 搜索树
1.1 概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有的结点都小于根结点的值
- 若它的右子树不为空,则右子树上所有的结点都大于根结点的值
- 它的左右子树也都分别是二叉搜索树
如下图,就是一棵二叉搜索树,二叉搜索树的中序遍历就是升序排列的

1.2 操作-查找
因为二叉搜索树天然就带有小的在左,大的在右的顺序,所以在查找的时候更加方便,类似于有天然的二分查找

代码实现如下:

1.3 操作 - 插入
按照二叉搜索树,小的在左边,大的在右边逻辑确定插入位置,插入新结点。因为要插入的结点最终都是称为叶子结点,所以光定义一个cur来表示要插入的结点还不够,还要定义一个parent结点来表示cur的父亲结点。
代码如下:

但上面代码的逻辑性还是有问题的,插入操作,并没有考虑到,如果要插入的树是一棵空树,即root == null的情况,会出现空指针的异常。
修正:

1.4 操作 - 删除(难)
搜索二叉树的删除是会发生很尴尬的情况的
如下图:

如果要删除值为8的结点,是很方便的,可以将7结点的right连接到值为9的结点。

但如果删除的是左边的值为1的结点呢?
删除了之后,3的left是连接值为2的结点呢?还是连接值为0的结点呢?这样就会出现尴尬的情况,采用的方法是替换法(也称替罪羊法),即可以在要删除的结点的右子树中,寻找一个值最小的叶子节点,换个方式讲是,找到要删除的结点的右子树的最左边子树(有点绕,可以多多理解一下),然后用这个最左边子树的值来覆盖要删除的结点的值,然后将最左边子树的结点删除。注意是覆盖,并不是将要删除的结点真的删除了,最终删除的结点是要删除的结点的右子树的最左边子树的结点。
举例:
如果要删除的结点是值为90的结点

先找到90结点的右子树为值为120的结点,然后再找到右子树120的最左边子树,即值为95的结点,用这个结点的值95来覆盖掉要删除的结点90的值,然后删除值为95的这个结点,如何删除呢?如果值为95的这个结点仍有有右子树呢?(注意:值为95的这个结点不可能再有左子树了,因为我们要在前面的操作中找的就是 要删除的结点的右子树的最左子树)就把值为95的结点的右子树连接到值为120的结点的left上即可。
(上面只是一种方式,是找到 要删除结点 的 右子树 的最左侧子树,同理, 也可以找到 要删除的结点 的 左子树 的最右侧子树,都相反一下即可,此处以右子树的最左侧左子树来研究)
代码实现:
设待删除结点为cur,带删除结点的双亲结点为parent

在删除中,有多种情况:

1.1情况:cur为root 且 cur.left == null 如下图,此时直接将cur的left赋值为root即可

删除后的效果:

1.2情况:cur不是root,cur.left == null,cur在左子树上,即cur 是 parent.left 如下图的效果,此时要删除的结点是值为40的结点,直接parent.left = cur.right即可

1.3 情况:cur不是root,cur.left == null cur是parent.right,即cur在右子树上,如下图情况,则直接parent.right = cur.right即可


2.1情况 cur.right == null cur是root 则直接root = cur.left即可
2.2情况:cur不是root cur是parent.left 且cur.right == null 则parent .left = cur.left
2.3 cur不是root cur是parent.right 且cur.right == null 则parent.right = cur.left

![]()
即使用前面所述的替代法。
代码实现如下:
下面的代码实现是前面的删除逻辑

替代法因为要向下找到要删除结点 的 右边子树 的 最左边子树,所以还需要一个寻找的逻辑,定义一个targetParent和target来寻找找最左子树
当结束上面的while循环时候,即target指向的是最左子树结点,然后cur.val = target.val进行覆盖
如下图所示:要删除的结点是cur,t是要删除节点 的 右边结点 的 最左侧结点,将cur的值覆盖为95,然后将 t 结点删掉(targetParent.left = target.right)(注意:删除的时候不要直接targetParent.left = null 因为target可能有右节点 也可能 没有右节点)

则代码如下:

但上面代码还是存在逻辑漏洞
如果是下图的情况,cur为值为95的结点,在while循环结束后,t指向的是值为120的结点,直接执行targetParent.left = target.right 就乱套了
所以还应该加一个 if 条件 即:if(taregt == targeParent.left)的时候,才能targetParent.left = target.right;否则应该是targetParent.right = target.right;
则替代法的实现代码应该是:

完整的删除代码如下:
public void remove(int val) {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 {//删除的逻辑removeNode(parent,cur);return;}}}private void removeNode(TreeNode parent, TreeNode cur) {if(cur.left == null) {if(cur == root) {root = cur.right;} else if(cur == parent.right) {parent.right = cur.right;} else {parent.left = cur.right;}} else if(cur.right == null) {if(cur == root) {root = cur.left;} else if(cur == parent.right) {parent.right = cur.left;} else {parent.left = cur.left;}} 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;}}}
1.5 性能分析:
插入和删除的操作都必须先查找,所以查找的效率可以代表二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找商都是结点在二叉搜索树的函数,即节点越深,则比较的次数就越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最好情况下:二叉搜索树为完全二叉树,平均比较次数为logN
最坏情况下:二叉搜索树退化为单分支树,其平均比较次数为:N / 2
可以及逆行改进,使得不管按照什么次序插入关键码,都可以使得二叉搜索树的性能最佳 -- 数据结构高阶时候学习!
2. 搜索
2.1 概念及场景
Map和Set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。之前常见的搜索方式有:
- 直接遍历:时间复杂度为O(N),元素如果比较多的话,效率较低。
- 二分查找:时间复杂度为O(logN),但搜索前必须要求序列是有序的
上述方式比较适合静态类型的数据进行查找,即一般不会对区间内进行插入和删除操作了,但在现实情况中的查找:1. 根据姓名查询考试成绩 2. 通讯录,即根据姓名查询联系方式 3. 不重复集合,即需要先搜索关键字是否已经在集合中,可能在查找的过程中进行一些插入和删除的操作,即动态查找,那上述两种方式就不合适了,这里介绍的Map和Set是一种适合动态查找的集合容器。
2.2 模型
一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型有两种:
- 纯Key模型,比如 有一个英文词典,快速查找一个单词是否收录在该词典中
- Key-Value模型,比如,梁山好汉的绰号
而Map中存储的就是key-value键值对,Set中只存储了Key。
3. Map的使用
Map官方文档:Map (Java Platform SE 8 )

3.1 Map的说明:
Map是一个接口类,并没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不能重复。
3.2 关于Map.Entry<K,V>的说明
Map.Entr<K,V>是Map内部实现的用来存放<key,value>键值对映射关系的内部类,该内部类中主要提供了key和value的获取,value的设置以及key的比较方式
注意:Map.Entry<K,V>并没有提供设置Key的方法
3.3 Map的常用方法说明

注意:
- Map是一个接口,不能直接实例化对象,如果要实例化对象是能实例化其实现类TreeMap或者HashMap。
- Map中存放键值对的Key是唯一的,value是可以重复的
- 在TreeMap中插入键值对时,key不能为空,否则会抛出空指针异常,但value可以为空,在HashMap中,key和value都可以为空
- Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)
- Map中的value可以全部分离出来,存储在Collection的任何一个子集中(value可能有重复)。
- Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

3.4 TreeMap的使用案例




getOrDefault方法的源码:






完!
相关文章:
java数据结构_Map和Set_9.1
1. 搜索树 1.1 概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有的结点都小于根结点的值若它的右子树不为空,则右子树上所有的结点都大于根结点的值…...
横向移动靶场-Tr0ll: 3
Tr0ll: 3来自 <Tr0ll: 3 ~ VulnHub> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182,靶场IP192.168.23.187 3,对靶机进行端口服务探测 …...
请解释 Node.js 中的网络模块(http、https),如何创建 HTTP服务器?
1. Node.js 中的网络模块(http 和 https) 原理与作用: Node.js 的 http 和 https 模块是内置的核心模块,用于创建 HTTP 和 HTTPS 服务器。 http 模块基于 Node.js 的事件驱动架构,利用 libuv 和 HTTP parser 库高效处…...
【WPF命令绑定之--没有Command属性的控件如何进行命令绑定?】
前言 C#WPF之命令绑定 内容 有些控件不支持直接绑定命令,可以调用其他依赖实现命令的绑定。 依赖:Microsoft.Xaml.Behaviors.Wpf 使用如下代码可以实现事件的命令绑定,及传递参数: 1、引用:xmlns:behavior“http://sch…...
记20忘10之六:line
记20忘10之六:line 胖子定律:每天坚持多咬两口,相信将来自己就是个胖子 今天,我们继续来记几个单词吧, line n.线 moral bottom line道德底线 派生、同源或相关: linear a.线的,直线的lineamen…...
【愚公系列】《Python网络爬虫从入门到精通》036-DataFrame日期数据处理
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…...
【系统稳定性】1.11 QVM稳定性问题分析(一)
目录 写在前面 一,qvm进程异常 1.1 进程崩溃(Coredump) 1.2 进程卡死 1.3 进程重启 二,qvm进程异常分析过程 写在前面 在QVM(Quantum Virtual Machine)作为HOST QNX的Guest,同样会遇到重启、Watchdog(看门狗)等稳定性问题。 这里我们把qvm的异常归类为两类问题…...
使用ChatGPT-Deep Reaserch两步给出文献综述!
文献综述是学术论文写作中不可或缺的一部分,它不仅是对已有研究的梳理和总结,更是为后续研究奠定理论基础的关键步骤。通过文献综述研究者能够全面了解当前研究领域的现状、主要观点和研究方法,从而找到自己研究的切入点和创新点。这一过程需…...
从0开始的操作系统手搓教程14——进一步完成中断子系统
目录 所以,如何查看我们的IDT呢 改进我们的中断处理hook 对8253编程,提升系统的频率 导论 控制字说明 说一下每个方式——概论 说一说计数器如何进行计时 方式0 方式1 方式2 方式3 方式4 方式5 回到问题,我们如何设置单次触发冲…...
小米火龙CPU和其他几代温度太高的CPU是由谁代工的
小米火龙CPU”并非小米自研芯片,而是指搭载在小米手机上的部分高通骁龙处理器因发热问题被调侃为“火龙”。以下是几款被称为“火龙”的高通CPU及其代工情况: 骁龙810 骁龙810是高通历史上最著名的“火龙”之一,采用台积电20nm工艺代工。由于…...
Educational Codeforces Round 174 (Rated for Div. 2)
Problem - B - Codeforces 之前没思路,我看了看答案。 思路不就来了: 简而言之,BFS那样遍历周围(上下左右均一次),如果有同色,就把这部分相邻的隔开,可以得到两块陌生人集合&#x…...
微服务即时通信系统---(七)文件管理子服务
目录 功能设计 模块划分 业务接口/功能示意图 服务实现流程 服务代码实现 封装文件操作模块(utils.hpp) 获取唯一标识ID 文件读操作 文件写操作 编写proto文件 文件元信息 文件管理proto 单文件上传 多文件上传 单文件下载 多文件下载 RPC调用 服务端创建子…...
mosfet的驱动设计-开关损耗
目录 1.开关时的DS损耗 2.导通损耗 3.截止损耗 4.驱动损耗 mos管的损耗主要有开关损耗和导通损耗两部分,开关损耗包括mos管开通是消耗的能量和在mos在线性区产生的损耗。导通损耗是由mos的导通电阻电阻消耗的能量。 mos的实际模型 我们先来感性的…...
Unity3D 对象实例化详解
前言 在Unity3D中,对象的实例化是游戏开发中非常常见的操作。无论是生成敌人、道具,还是动态创建UI元素,实例化都是实现这些功能的核心技术之一。本文将详细介绍Unity3D中对象实例化的原理、技术细节以及代码实现。 对惹,这里有…...
萌新学 Python 之 with 文件操作语句
with 语句用于资源管理,避免资源泄露,对文件操作时,不管文件是否有异常,都会自动清理和关闭 with 语句的格式: with open(文件路径, mode模式, encodingutf-8) as file_obj: # as 取别名print(对文件进行操作&…...
C# Unity 唐老狮 No.2 模拟面试题
本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho 如果你发现了文章内特殊的字体…...
FFmpeg-chapter3-读取视频流(原理篇)
ffmpeg网站:About FFmpeg 1 库介绍 (1)libavutil是一个包含简化编程函数的库,包括随机数生成器、数据结构、数学例程、核心多媒体实用程序等等。 (2)libavcodec是一个包含音频/视频编解码器的解码器和编…...
Docker迁移/var/lib/docker之后镜像容器丢失问题
迁移/var/lib/docker时,如果目标目录少写一个/,/etc/docker/daemon.json中的data-root后面需要多加一级目录docker。 若迁移命令如下 rsync -avz /var/lib/docker /home/docker/ 在/etc/docker/daemon.json中添加如下内容 "data-root": &q…...
单片机中的flah和RAM
片机的 Flash 和 RAM 是两种关键的内存类型,分别用于存储程序代码和运行时数据。 Flash 存储器 用途:用于存储程序代码(如固件)和常量数据(如查找表、字符串等)。 特点: 非易失性:断…...
【Pytest】setup和teardown的四个级别
文章目录 1.setup和teardown简介2.模块级别的 setup 和 teardown3.函数级别的 setup 和 teardown4.方法级别的 setup 和 teardown5.类级别的 setup 和 teardown 1.setup和teardown简介 在 pytest 中,setup 和 teardown 用于在测试用例执行前后执行一些准备和清理操…...
第8天:面向对象编程入门 - 类与对象
第8天:面向对象编程入门 - 类与对象 一、📚 今日学习目标 🎯 掌握类与对象的定义与使用🔧 理解封装、继承、多态三大特性💡 完成银行账户管理系统实战🛠️ 学会构造函数与析构函数的编写 二、⚙️ 核心知…...
单细胞marker基因表达密度图-(还有一个包装函数)
有小伙伴说想要做单细胞marker基因表达密度图,我一想,好像之前是做过的(单细胞marker基因可视化的补充---密度图与等高线图)。但是他又说没有文献中的效果。后来我一看,是因为着色的问题。其实用Nebulosa包(…...
python多线程之Event机制笔记
Event 事件 笔记 1. 基本概念 threading.Event 是 Python 线程同步的基础组件,本质是一个布尔标志位,提供跨线程的事件通知机制。 2. 核心方法 方法作用描述set()设置事件为 True,唤醒所有等待线程clear()重置事件为 Falsewait(timeoutNo…...
记忆化搜索与动态规划:原理、实现与比较
记忆化搜索和动态规划是解决优化问题的两种重要方法,尤其在处理具有重叠子问题和最优子结构性质的问题时非常有效。 目录 1. 记忆化搜索(Memoization) 定义: 实现步骤: 示例代码(斐波那契数列࿰…...
架构师面试(九):缓存一致性
问题 关于【数据库和缓存】一致性,下面哪几项是在线上生产环境中相对合理的处理方式? A. 对于查询操作,先查缓存,如果为空则查 DB,然后将数据带入缓存; B. 对于插入操作,只写 DB 即可&#…...
Spring Boot集成Spring Ai框架【详解 搭建Spring Ai项目,以及简单的ai大模型智能体应用,附有图文+示例代码】
文章目录 一.Spring Ai介绍1.0 认识Spring Ai1.1 特征1.1 大模型专业名字介绍1.1.1 RAG(检索增强生成)RAG 的基本原理RAG 的关键技术RAG 的优势RAG 的应用场景 1.1.2 fine-tuning(微调)1.1.3 function-call(函数调用) 1.2 创建简单的Spring Ai项目 二.Spring Ai简单的智能应用2…...
OpenHarmony启动系统-U-Boot简介和源码下载与编译
OpenHarmony系统启动流程简述 设备上电后,OpenHarmony系统大致经历以下3个阶段: 1.BootRom代码引导加载UBoot; 2.UBoot启动初始化硬件资源,引导并加载系统内核(Linux内核); 3.Kernel(LiteOs,Linux内核)启动、加载驱动…...
Metal 学习笔记六:坐标空间
要在网格上轻松找到一个点,您需要一个坐标系。例如,如果网格恰好是您的 iPhone 15 屏幕,则中心点可能是 x:197、y:426。但是,该点可能会有所不同,具体取决于它所处的空间。 在上一章中…...
React + TypeScript 实现 SQL 脚本生成全栈实践
React TypeScript 实现数据模型驱动 SQL 脚本生成全栈实践 引言:数据模型与 SQL 的桥梁革命 在现代化全栈开发中,数据模型与数据库的精准映射已成为提升开发效率的关键。传统手动编写 SQL 脚本的方式存在模式漂移风险高(Schema Drift&#…...
执行git操作时报错:`remote: [session-b8xxxda3] Access denied ...`解决方案
问题描述: 执行git push -u origin "master"时报错: > remote: [session-b849cda3] Access denied > fatal: unable to access https://gitee.com/jyunee/maibobo.git/: The requested URL returned error: 403表示没有权限访问远程仓库…...
