一:TreeMap整体认识

我们知道HashMap,它保证了以O(1)的时间复杂度进行增、删、改、查,从存储角度考虑,这两种数据结构是非常优秀的。但是HashMap还是有自己的局限性----**它不具备统计性能,或者说它的统计性能时间复杂度并不是很好才更准确,所有的统计必须遍历所有Entry,因此时间复杂度为O(N)**。

比如Map的Key有1、2、3、4、5、6、7,我现在要统计:

1. 所有Key比3大的键值对有哪些

2. Key最小的和Key最大的是哪两个

就类似这些操作,HashMap做得比较差,此时我们可以使用TreeMap。TreeMap的Key按照自然顺序进行排序或者根据创建映射时提供的Comparator接口进行排序。TreeMap为增、删、改、查这些操作提供了log(N)的时间开销,从存储角度而言,这比HashMap的O(1)时间复杂度要差些;但是在统计性能上,TreeMap同样可以保证log(N)的时间开销,这又比HashMap的O(N)时间复杂度好不少。

因此:如果只需要存储功能,使用HashMap是一种更好的选择;如果还需要保证统计性能或者需要对Key按照一定规则进行排序,那么使用TreeMap是一种更好的选择。

TreeMap是由红黑树来实现的,下面看一下红黑树

二:红黑树

红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。

我们知道一颗基本的二叉树他们都需要满足一个基本性质--即树中的任何节点的值大于它的左子节点,且小于它的右子节点。按照这个基本性质使得树的检索效率大大提高。我们知道在生成二叉树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样势必会导致二叉树的检索效率大大降低(O(n)),所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,如:AVL,SBT,伸展树,TREAP ,红黑树等等。

平衡二叉树必须具备如下特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。也就是说该二叉树的任何一个等等子节点,其左右子树的高度都相近。

红黑树顾名思义就是节点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。对于一棵有效的红黑树二叉树而言我们必须增加如下规则:

1. 每个节点都只能是红色或者黑色

2. 根节点是黑色

3. 每个叶节点(NIL节点,空节点)是黑色的。

4. 如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这棵树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。所以红黑树它是复杂而高效的,其检索效率O(log n)。下图为一颗典型的红黑二叉树。

三:源码分析

类信息

TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。

属性信息

节点的Entry内部类信息

put方法

put方法步骤如下:

1.获取根节点,根节点为空,产生一个根节点,将其着色为黑色,退出余下流程

2.获取比较器,如果传入的Comparator接口不为空,使用传入的Comparator接口实现类进行比较;如果传入的Comparator接口为空,将Key强转为Comparable接口进行比较

3.从根节点开始逐一依照规定的排序算法进行比较,取比较值cmp,如果cmp=0,表示插入的Key已存在;如果cmp>0,取当前节点的右子节点;如果cmp<0,取当前节点的左子节点

4.排除插入的Key已存在的情况,第(3)步的比较一直比较到当前节点t的左子节点或右子节点为null,此时t就是我们寻找到的节点,cmp>0则准备往t的右子节点插入新节点,cmp<0则准备往t的左子节点插入新节点

5.new出一个新节点,默认为黑色,根据cmp的值向t的左边或者右边进行插入

6.插入之后进行修复,包括左旋、右旋、重新着色这些操作,让树保持平衡性

第1~第5步都没有什么问题,红黑树最核心的应当是第6步插入数据之后进行的修复工作,对应的Java代码是TreeMap中的fixAfterInsertion方法

get方法

get方法相当于put方法就简单多了,从根节点开始循环比较。

  • 当key大于当前节点,把当前节点指针指向左孩子继续循环。
  • 当key小于当前节点,把当前节点的指针指向右孩子继续循环。
  • 当key等于当前节点,则返回当前节点。

remove方法

针对于红黑树的增加节点而言,删除显得更加复杂,使原本就复杂的红黑树变得更加复杂。同时删除节点和增加节点一样,同样是找到删除的节点,删除之后调整红黑树。但是这里的删除节点并不是直接删除,而是通过走了“弯路”通过一种捷径来删除的:找到被删除的节点D的子节点C,用C来替代D,不是直接删除D,因为D被C替代了,直接删除C即可。所以这里就将删除父节点D的事情转变为了删除子节点C的事情,这样处理就将复杂的删除事件简单化了。子节点C的规则是:右分支最左边,或者 左分支最右边的。

红-黑二叉树删除节点,最大的麻烦是要保持 各分支黑色节点数目相等。 因为是删除,所以不用担心存在颜色冲突问题——插入才会引起颜色冲突。

红黑树删除节点同样会分成几种情况,这里是按照待删除节点有几个儿子的情况来进行分类:

1. 没有儿子,即为叶结点。直接把父结点的对应儿子指针设为NULL,删除儿子结点就OK了。

2. 只有一个儿子。那么把父结点的相应儿子指针指向儿子的独生子,删除儿子结点也OK了。

3. 有两个儿子。这种情况比较复杂,但还是比较简单。上面提到过用子节点C替代代替待删除节点D,然后删除子节点C即可。

删除后的调整

删除元素之后的调整和前面的插入元素调整的过程比起来更复杂。它不是一个简单的在原来过程中取反。我们先从一个最基本的点开始入手。首先一个,我们要进行调整的这个点肯定是因为我们要删除的这个点破坏了红黑树的本质特性。而如果我们删除的这个点是红色的,则它肯定不会破坏里面的属性。因为从前面删除的过程来看,我们这个要删除的点是已经在濒临叶节点的附近了,它要么有一个子节点,要么就是一个叶节点。如果它是红色的,删除了,从上面的节点到叶节点所经历的黑色节点没有变化。所以,这里的一个前置条件就是待删除的节点是黑色的。

在前面的那个前提下,我们要调整红黑树的目的就是要保证,这个原来是黑色的节点被删除后,我们要通过一定的变化,使得他们仍然是合法的红黑树。我们都知道,在一个黑色节点被删除后,从上面的节点到它所在的叶节点路径所经历的黑色节点就少了一个。我们需要做一些调整,使得它少的这个在后面某个地方能够补上。

java 二叉树的高度_吃透Java集合系列十二:TreeMap相关推荐

  1. java死锁业务场景_【深入浅出多线程系列十二】:什么是死锁?(场景+代码示例)...

    在学习Java的道路上,是否路过多线程时总让你很迷惘:很不巧,我也是,而使我们感到很迷惘主要原因都源于没有对概念的深深的理解和实践.所以我决定漫步Java多线程,同你一起会会多线程. 多线程系列 多线 ...

  2. java 二叉树的高度_最全二叉树:完整详解二叉树的遍历以及完全二叉树等6种二叉树...

    树在数据结构中占据了非常重要的位置,尤其是二叉树.经常是在java面试中必问的一个环节,而且二叉树的应用场景真的非常普遍,需要重点掌握好. 但是一直以来,很多同学对于二叉树的掌握都是不太全面.今天我就 ...

  3. java volatile线程可见_吃透Java并发:volatile是怎么保证可见性的

    前言 volatile关键字能够保证可见性和有序性,但是volatile为什么能够保证可见性和有序性?为什么volatile又不能保证原子性? 今天,我们从CPU多核缓存架构出发,结合MESI缓存一致 ...

  4. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  5. java模式设计视频教程_全新JAVA设计模式详解视频教程 完整版课程

    ├─0-设计模式前言.mp4; D" g8 v: S4 L* d2 y* U  j ; N5 }! y5 r/ k3 B5 ]+ f% [: x├─1-strategy_策略模式-第二模式. ...

  6. 【零基础学Java】—Random的基本概述和使用(十二)

    [零基础学Java]-Random的基本概述和使用(十二) Random类用来生成随机的数字,使用起来也是三个步骤 导包:import java.util.Random; 创建:Random r=ne ...

  7. kotlin杂谈系列十二(Kotlin和Java的互操作)

    Kotlin杂谈系列十二 这次就主要来谈谈kotlin和java互操作的问题 kotlin出来的使命就是为了解决java的模板问题和一些冗长的问题所以kotlin天生就很好的支持了java 所以我们在 ...

  8. Android简易音乐重构MVVM Java版-新增推荐菜单及侧边栏展示(十二)

    Android简易音乐重构MVVM Java版-新增推荐菜单及侧边栏展示(十二) 关于 效果图 添加侧边栏 添加推荐歌单 新增RecommendAdapter适配器 修改DiscoverFragmen ...

  9. java二叉树是什么_树的基本概念以及java实现二叉树

    树具有的特点有: (1)每个结点有零个或多个子结点 (2)没有父节点的结点称为根节点 (3)每一个非根结点有且只有一个父节点 (4)除了根结点外,每个子结点可以分为多个不相交的子树. 树的基本术语有: ...

最新文章

  1. Distributed Systems笔记-middlewares
  2. gj13 asyncio并发编程
  3. ExtAspNet应用技巧(十七) - 新增菜单
  4. 用户zabbix@localhost的访问被拒绝(使用密码:yes)_Coinbase意外地保存了3420个客户的未加密密码...
  5. Xgboost中特征重要性计算方法详解
  6. 4 pwm 什么时候采样电流_电机控制之电流采样及坐标变换第一部分
  7. 廖雪峰python教程官网-廖雪峰老师官方爬虫教程,13个案例带你全面入门
  8. jquery-weui的学习与使用
  9. 怎么在win7上安装AIR780E的USB驱动
  10. [转载]INNO SETUP注册DLL文件
  11. 怎么将几张pdf合并成一张_Adobe Acrobat怎么将多个PDF文件合并成一个pdf页面?
  12. 云服务服务器免费使用
  13. 私密聊天加密聊天伪装界面聊天软件产品UI分析,qiaoyu5,feige5
  14. IE8 使用 Oracle ERP
  15. ODOO11报价单确认订单创建入库单(_run_move)
  16. usaco training 4.4.1 Shuttle Puzzle 题解
  17. 不停留在表面,天搜科技让创新更接地气
  18. Mybatis配置Mapper踩过的坑
  19. Android 短信验证码自动填写
  20. fota 差分包_FOTA相关知识总结

热门文章

  1. 空间滤波-统计排序滤波器-修正阿尔法均值滤波器
  2. o.boj 1451 贪吃的Tomato
  3. 局域网推流在学术会议现场应用
  4. t3修改计算机后就无法登录了,在电脑中登录用友T3失败的具体解决方法介绍
  5. mysql 慢sql 十几秒_sql优化之慢sql耗时排查
  6. 《30天》的汇编实现(二)
  7. 基于golang做一个简易私有网盘
  8. BA-siemens-ppm模块调试
  9. 趣味编程-现代诗词中的高频词语
  10. 2022-3-25 06.字符串压缩