映射表map(平衡二叉树实现)_手动实现Java集合容器之TreeMap(上)

2b8b1b800102ed6f140738c0052ef495.png

上一篇我们手写了HashMap,还有一个很重要的Map的实现类TreeMap。打开源码第一句话:* A Red-Black tree based {@link NavigableMap} implementation.TreeMap是一个基于红黑树的实现。对红黑树没有了解怎么办,那就先搞清楚红黑树的原理。只要理解红黑树的玩法,TreeMap实现起来就没有那么大的难度了。

红黑树(Red Black Tree) 是一种自平衡二叉查找树。所以我们先搞明白什么是二叉查找树和完美平衡二叉树。

二叉排序树(Binary Sort Tree)是具有下列性质的二叉树:

  1. 元素以关键字为依据,每个结点可比较大小,各元素关键字互不相同。
  2. 对于每个结点,其左子树上所有结点均小于该结点,右子树上所以结点均大于该结点。
  3. 每个结点的左右子树也分别为二叉排序树。

b32809c93ca284d1fa2acacdec43dfba.png
  • 查找:从根结点开始查找,根据每一次比较结果,在当前结点的左子树与右子树选择其一,从而缩小一半的查找范围。如果到达叶子结点仍然不相等,则查找不成功。
  • 插入:首先使用查找算法确定元素的插入位置。如果查找成功,说明相同元素已经存在,则不插入;否则在查找不成功的一条路径之尾插入结点,作为叶子结点。
  • 删除:a. 叶结点直接删除 b. 如果被删除的结点有一个子结点,将子结点移到被删除的元素的位置。c. 采用中序遍历(左-根-右),找到待删除的结点的后继结点,将其与待删除的结点互换,然后删除待删除的结点。假如我们要删除29,中序遍历结果为10-11-13-20-27-29-31-32-39-41-53-50-65-72-91,所以29的后继结点是31,然后互换位置,删除29。
  • 二叉查找树的查询复杂度,和二分查找一样,插入和查找的时间复杂度均为 O(logn) ,但是在最坏的情况下仍然会有 O(n) 的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。

5f16961221595e71d9d150c28a445771.png

为了降低二叉排序树的高度,提高查找效率。平衡二叉树(又称为AVL树)。平衡二叉树(Balanced Binary Tree)是具有下列性质的二叉排序树:

  1. 左子树和右子树都是平衡二叉树
  2. 左子树与右子树高度差绝对值不超过一。结点的平衡因子定义为其左子树与右子树的高度之差。
  3. 在平衡二叉树中,插入或删除一个结点可能破坏二叉树的平衡性,因此在插入或删除时都要调整二叉树。

插入:如果插入一个结点后破坏了二叉树的平衡性,需要调整一棵最小不平衡子树。最小不平衡子树是离插入结点最近,且以平衡因子绝对值大于1的结点为根的子树。若出现不平衡,则要根据新插入的结点与最低不平衡结点的位置关系进行相应的调整。分为LL,RR,LR,RL四种类型。以下只介绍了最简单的情况。

LL型:在最低不平衡结点的左孩子的左子树上插入结点。插入C后,A的平衡因子由1增加到2 。结点B变成新的根结点。A变成右孩子结点,C变成左孩子结点。

d678019b658951de9bbe112c1a82fcc1.png

RR型:在最低不平衡结点的右孩子的右子树上插入结点。结点B变成新的根结点。C变成右孩子结点,A变成左孩子结点。

f7ff879e160b2f30de4ae8fd50968652.png

LR型:在最低不平衡结点的左孩子的右子树上插入结点。结点C变成新的根结点。A变成右孩子结点,B变成左孩子结点。

0bb9c8252462b2e18b97a9cc0f90e5e3.png

RL型:在最低不平衡结点的右孩子的左子树上插入结点。结点C变成新的根结点。B变成右孩子结点,A变成左孩子结点。

246abb2c5de8efa581d8a8304cd93281.png

平衡二叉树似乎完美解决了二叉排序树的问题,通过旋转使树的高度最小化,对于有 n 个节点的平衡树,最坏的查找时间复杂度也为 O(logn)。

那么我们为什么还需要红黑树?

因为我们不仅仅需要关心查找的效率,还要考虑插入的效率。因为平衡二叉树要求每个节点的左子树和右子树的高度差至多等于1,这个要求非常严格,每次进行插入/删除数据的时候,几乎都会破坏这个规则。在插入/删除数据很频繁的场景中,平衡二叉树的性能就会受到很严重的影响。所以我们需要红黑树。

红黑树的定义

  1. 每个节点或者是黑色,或者是红色。
  2. 根节点是黑色。
  3. 每个叶子节点是黑色。
  4. 如果一个节点是红色的,则它的子节点必须是黑色的
  5. 从任意一个节点到叶子节点,经过的黑色节点是一样的。
  • 查找:红黑树的查找和二叉排序树一样,不再赘述
  • 添加:
这是一个把数据结构可视化的网站,我们用网站进行一些插入数据的试验
Red/Black Tree Visualization​www.cs.usfca.edu

fd863e5a316afc42a005b21e921f5b1c.png
添加根结点时,结点为黑色

906cca49372f03fd18cb1ab1fb10e6e5.png
添加一个子结点,插入结点为红色,满足红黑树的定义,无需变化

f0f0f47b0596b7b51a4156c2ffde965c.png
在添加一个孩子,如果添加的数比根结点小,很简单

199c1e0f33c2df9e79301a8076db1af6.png
如果添加的数比根结点的右结点还要大,左旋,15变成根结点,并且改变颜色

21670ad79273e48719077ad5a85cac1a.png
如果继续插入一个数,因为不满足性质4,所以10和20的颜色变黑,30变红

1b742f3727f86f7406cded743f06b104.png
继续在右子树上添加35,左旋

3a0d9b919a9cb60d8f02b82021bf0dba.png
继续插入25,此时不需要旋转,只需要改变结点颜色,满足性质四

所以我们发现每一次插入数据之后,如果不满足红黑树的定义,就需要对红黑树的结构进行调整。两种方式:旋转和重新上色。所以我们在Java源码中找到了添加数据的方法,并分析这个方法。

/**

c7f1a613b0a0931d55dae88e32e5c3ed.png
假如我们要往这个红黑数里面添加6

ff5b8d852422b7baefd2cc92c24cfaae.png
没有调整过的树是这样的

44f797d2d9890910866e5426f39c9d8d.png
第一步,8和6两个同为红色结点,所以改变颜色,8和14变黑,10变红。对应源码中的情况1,当插入结点的叔叔结点为红,把父结点变黑,叔叔结点也变黑,再把爷爷结点变红

5886a970c7f1b1f845db88f3eff68f1a.png
如果插入结点的爷爷结点是右孩子结点,我们找到爷爷结点的父结点,然后在这个结点上左旋,对应源码中的情况2

e980fcbd191068ea0f4226a631d1253e.png
下一步,右旋,10变黑,20变红,对应源码中的情况3

从源码中看出,情况2是情况3的一种扩展。情况4、5、6是1、2、3的镜像,就不展开了。

删除也需要调整树的结构,但是更复杂一些,我们看一下源码中的方法。

/**

删除一共8种情况,1-4和5-8也是镜像的,就不举具体的例子了。TreeMap果然要比HashMap还要复杂的多,就算读懂了 rebalance的方法,真正实现起来还是有很大的难度。以此为基础,下一篇我们尝试一下手写HashMap。

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

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

相关文章

wltc循环多少公里_原来所有车都烧机油!但是烧多少才算正常你知道吗?

点击上方“腾讯汽车”关注我们,最新汽车资讯,最方便的用车常识还有最萌的小编都在这里啦!最为当今汽车用户最为关心的问题,烧机油现象被很多用户当做引擎是好是坏的重要标准。但根据机油在引擎内冷却及清理引擎内杂质的循环机制来…

LeetCode 1806. 还原排列的最少操作步数(模拟)

文章目录1. 题目2. 解题1. 题目 给你一个偶数 n​​​​​​ ,已知存在一个长度为 n 的排列 perm ,其中 perm[i] i​(下标 从 0 开始 计数)。 一步操作中,你将创建一个新数组 arr ,对于每个 i &#xff…

python3经典实例_Python3十大经典错误及解决办法

接触了很多Python爱好者,有初学者,亦有转行人。不论大家学习Python的目的是什么,总之,学习Python前期写出来的代码不报错就是极好的。下面,严小样儿为大家罗列出Python3十大经典错误及解决办法,供大家学习。…

LeetCode 1807. 替换字符串中的括号内容(哈希map)

文章目录1. 题目2. 解题1. 题目 给你一个字符串 s ,它包含一些括号对,每个括号中包含一个 非空 的键。 比方说,字符串 "(name)is(age)yearsold" 中,有 两个 括号对,分别包含键 “name” 和 “age” 。 你知…

bootice.exe linux 启动盘,下载BOOTICE来把你的U盘做成启动盘

为了方便维护电脑,需要制作一个合适的U盘启动盘。网上制作U盘启动盘的工具也有很多,我下面使用bootice这个U盘启动盘制作工具来制作U盘启动盘。下载BOOTICE1、BOOTICE>分区管理G,对U盘进行格式化,FAT16,卷标设置为G…

excel打开空白_啥?下载的文件显示“文件已损坏,无法打开”?

推荐文章:Windows10系统的优化工具神器对于一个开发人员的我,这两天在网站做一个导出Excel表格功能,遇到了一个坑。在本地测试导出并且可以打开,但是到了测试环境导出打开却显示“文件已损坏,无法打开”。刚开始以为是…

erp故障处理流程图_PLC故障常见原因及处理方法!

欢迎关注“热控圈 ” ID:rekongquan传播热控知识,分享技术精华!第一部分、运行中PLC故障常见原因及处理方法(一)、外围电路元器件故障此类故障在PLC工作一定时间后的故障中经常发生。在PLC控制回路中如果出现元器件损坏故障,PLC控…

LeetCode 1808. 好因子的最大数目(整数拆分,乘积最大)

文章目录1. 题目2. 解题1. 题目 给你一个正整数 primeFactors 。你需要构造一个正整数 n ,它满足以下条件: n 质因数(质因数需要考虑重复的情况)的数目 不超过 primeFactors 个。n 好因子的数目 最大化。 如果 n 的一个因子可以…

安卓apk签名提取工具_Android测试工具入门介绍(二)

今天我们来讲讲一款牛逼的安卓集成工具:就是大名还算顶顶的AndroidKill;先来个软件界面截图:多么简单有华丽的界面啊!我说的是功能华丽,该有的功能他都有。首先我们先点开菜单中的Android,配置下APKTOOL管理…

atoi函数_每日一道 LeetCode (50):字符串转换整数 (atoi)

❝每天 3 分钟,走上算法的逆袭之路。❞前文合集每日一道 LeetCode 前文合集代码仓库GitHub:https://github.com/meteor1993/LeetCodeGitee:https://gitee.com/inwsy/LeetCode题目:最长回文子串难度:「中等」题目来源&a…

面向对象4大特性的作用

文章目录1. 封装2. 抽象3. 继承4. 多态学习自 极客时间《设计模式之美》 1. 封装 隐藏保护内部数据,不被随意修改,提高可维护性仅暴露必要的接口,提高易用性 2. 抽象 提高代码可扩展、可维护性,修改不需要改变定义,…

远程连接Kali Linux使用PuTTY实现SSH远程连接

远程连接Kali Linux使用PuTTY实现SSH远程连接 本书主要以在Android设备上安装的Kali Linux操作系统为主,介绍基于Bash Shell渗透测试。由于在默认情况下,在Android设备上安装的Kali操作系统没有安装任何工具。如果直接在手机或平板上安装一些软件时&…

python 百度ocr安装_Python调用百度OCR实现图片文字识别的示例代码

百度AI提供了一天50000次的免费文字识别额度,可以愉快的免费使用!下面直接上方法: 首先在百度AI创建一个应用,按照下图创建即可,创建后会获得如下:创建后会获得如下信息: APP_ID ****** API_KE…

哪些代码设计看似是面向对象,实际是面向过程的?

文章目录1. 滥用 getter、setter 方法2. 滥用全局变量、全局方法3. 数据、方法分离学习自 极客时间《设计模式之美》 1. 滥用 getter、setter 方法 违反了封装特性,风格退化为面向过程编程 2. 滥用全局变量、全局方法 Constants 类 所有的常量都放在这个类中&…

vue 图片拖动加载 类似于地图_前端性能优化之图片懒加载(附vue自定义指令)...

作者:lzg9527链接:https://juejin.cn/post/6903774214780616718在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列表头图等。图片众多以及图片体积过大往往会影响页面加载速度&…

vant toast 指定挂载到指定位置_docker卷挂载技术

卷技术,容器内部数据映射到宿主机上一、直接使用命令来挂载docker run -it -v /home/test:/home centos /bin/bash# 在主机上查看 docker运行容器的id [rootlocalhost home]# docker ps CONTAINER ID IMAGE COMMAND CREATED …

数据仓库 Hive(内含大数据镜像下载)

文章目录1. 特点2. Hive 体系架构3. 安装 Hive3.1 安装 MySQL3.2 安装 Hive3.3 配置 Hive4. 实践4.1 函数4.2 Hive Shell安装没成功:直接用现成的镜像 大数据Linux实验环境虚拟机镜像文件 http://dblab.xmu.edu.cn/blog/1645-2/ cloudera-quickstart-vm-集成了大数据…

一台机器起多个filebeat_全自动多色丝印机一台多少钱?

全自动多色丝印机运用在于几种领域当中,其中比较常见的应该就是包装行业了。比如我们日常生活中,经常看到的洗发水外壳上,化妆品外壳上,膏霜瓶瓶身上等地方的图文,都是使用全自动多丝印机印刷来的。全自动多色丝印机是…

C语言做线性分析,C语言版的线性回归分析函数

前几天,清理出一些十年以前DOS下的程序及代码,看来目前也没什么用了,想打个包刻在光碟上,却发现有些代码现在可能还能起作用,其中就有计算一元回归和多元回归的代码,一看代码文件时间,居然是199…

python里str什么意思_Python 3 字符串中的 STR 和 Bytes 究竟有什么区别?

原标题:Python 3 字符串中的 STR 和 Bytes 究竟有什么区别? Python2的字符串有两种:str和Unicode,Python3的字符串也有两种:str和Bytes。Python2的str相当于Python3的Bytes,而Unicode相当于Python3的Bytes。…