近期学习了 HashMap 实现原理,这篇咱们了解一下红黑树的设计,相比 jdk1.7 的 HashMap 而言,jdk1.8最重要的就是引入了红黑树的设计,当hash表的单一链表长度超过 8 个的时候,链表结构就会转为红黑树结构。

01、故事的起因

JDK1.8 最重要的就是引入了红黑树的设计(当key值的hash值相同的链表长度超过 8 个的时候)
为什么要这样设计呢?好处就是避免在最极端的情况下链表变得很长很长,在查询的时候,效率会非常慢。

  • 红黑树查询:其访问性能近似于折半查找,时间复杂度 O(logn);
  • 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度 O(n);

本文主要是讲解红黑树的实现,只有充分理解了红黑树,对于之前的分析才会更加理解。

简单的说,红黑树是一种近似平衡的二叉查找树,其主要的优点就是“平衡“,即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度为 log(n)。

关于红黑树的内容,网上给出的内容非常多,主要有以下几个特性:

  • 1、每个节点要么是红色,要么是黑色,但根节点永远是黑色的;

  • 2、每个红色节点的两个子节点一定都是黑色;

  • 3、红色节点不能连续(也即是,红色节点的孩子和父亲都不能是红色);

  • 4、从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点;

  • 5、所有的叶节点都是是黑色的(注意这里说叶子节点其实是上图中的 NIL 节点);

在树的结构发生改变时(插入或者删除操作),往往会破坏上述条件 3 或条件 4,需要通过调整使得查找树重新满足红黑树的条件。

02、调整方式

上面已经说到当树的结构发生改变时,红黑树的条件可能被破坏,需要通过调整使得查找树重新满足红黑树的条件。

调整可以分为两类:一类是颜色调整,即改变某个节点的颜色,这种比较简单,直接将节点颜色进行转换即可;另一类是结构调整,改变检索树的结构关系。结构调整主要包含两个基本操作:左旋(Rotate Left),右旋(RotateRight)。

2.1、左旋

左旋的过程是将 p 的右子树绕 p 逆时针旋转,使得 p 的右子树成为 p 的父亲,同时修改相关节点的引用,使左子树的深度加 1,右子树的深度减 1,通过这种做法来调整树的稳定性。过程如下:

以 jdk1.8 为例,打开 HashMap 的源码部分,红黑树内部类 TreeNode 属性分析:


static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {//指向父节点的指针TreeNode<K,V> parent;//指向左孩子的指针TreeNode<K,V> left;//指向右孩子的指针TreeNode<K,V> right;//前驱指针,跟next属性相反的指向TreeNode<K,V> prev;//是否为红色节点boolean red;......
}

左旋方法 rotateLeft 如下:


static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,TreeNode<K,V> p) {//root:表示根节点//p:表示要调整的节点//r:表示p的右节点//pp:表示p的parent节点//rl:表示p的右孩子的左孩子节点TreeNode<K,V> r, pp, rl;//r判断,如果r为空则旋转没有意义if (p != null && (r = p.right) != null) {//多个等号的连接操作从右往左看,设置rl的父亲为pif ((rl = p.right = r.left) != null)rl.parent = p;//判断p的父亲,为空,为根节点,根节点的话就设置为黑色if ((pp = r.parent = p.parent) == null)(root = r).red = false;//判断p节点是左儿子还是右儿子else if (pp.left == p)pp.left = r;elsepp.right = r;r.left = p;p.parent = r;}return root;

2.2、右旋

了解了左旋转之后,相应的就会有右旋,逻辑基本也是一样,只是方向变了。右旋的过程是将 p 的左子树绕 p 顺时针旋转,使得 p 的左子树成为 p 的父亲,同时修改相关节点的引用,使右子树的深度加 1,左子树的深度减 1,通过这种做法来调整树的稳定性。实现过程如下:

同样的,右旋方法 rotateRight 如下:

static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,TreeNode<K,V> p) {//root:表示根节点//p:表示要调整的节点//l:表示p的左节点//pp:表示p的parent节点//lr:表示p的左孩子的右孩子节点TreeNode<K,V> l, pp, lr;//l判断,如果l为空则旋转没有意义if (p != null && (l = p.left) != null) {//多个等号的连接操作从右往左看,设置lr的父亲为pif ((lr = p.left = l.right) != null)lr.parent = p;//判断p的父亲,为空,为根节点,根节点的话就设置为黑色if ((pp = l.parent = p.parent) == null)(root = l).red = false;//判断p节点是右儿子还是左儿子else if (pp.right == p)pp.right = l;elsepp.left = l;l.right = p;p.parent = l;}return root;
}

03、操作示例介绍

3.1、插入调整过程图解

3.2、删除调整过程图解

3.3、查询过程图解

04、总结

至此,红黑树的实现就基本完成了,关于红黑树的结构,有很多种情况,情况也比较复杂,但是整体调整流程,基本都是先调整结构然后调整颜色,直到最后满足红黑树特性要求为止。如果有理解不当之处,欢迎指正!

05、参考资料

1、简书 - JDK1.8红黑树实现分析: https://www.jianshu.com/p/34b6878ae6de

2、知乎 - 史上最清晰的红黑树讲解: https://zhuanlan.zhihu.com/p/24810439?refer=dreawer

HashMap红黑树原理分析相关推荐

  1. HashMap红黑树原理解析

    HashMap红黑树原理解析 定义: 简单来说红黑树是一种近视平衡二叉查找树,主要优点是"平衡",即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度 ...

  2. HashMap红黑树原理及源码分析---图形、注释一应俱全

    目录 一.红黑树定义 二.节点新增原理: 三.红黑树的生成 2.1 一个节点 2.2 两个节点 2.3 三个节点 2.3.1 第二个节点作为root右子树情况下 2.3.2 第二个节点作为root左子 ...

  3. 为什么红黑树查询快_目前最详细的红黑树原理分析(大量图片+过程推导!!!)...

    一.为什么要有红黑树这种数据结构? 我们知道ALV树是一种严格按照定义来实现的平衡二叉查找树,所以它查找的效率非常稳定,为O(log n),由于其严格按照左右子树高度差不大于1的规则,插入和删除操作中 ...

  4. 目前最详细的红黑树原理分析(大量图片+过程推导!!!)

    一.为什么要有红黑树这种数据结构?   我们知道ALV树是一种严格按照定义来实现的平衡二叉查找树,所以它查找的效率非常稳定,为O(log n),由于其严格按照左右子树高度差不大于1的规则,插入和删除操 ...

  5. 数据结构-红黑树原理分析

    前言 在阅读HashMap源码的时候发现,java1.8的HashMap的链表实现增加了红黑树,当链表长度超过指定阈值8的时候回进行树化. 为了提高增删查的效率. 而红黑树又比较复杂,所以专门写一篇关 ...

  6. 遍历HashMap源码——红黑树原理、HashMap红黑树实现与反树型化(三)

    本章将是HashMap源码的最后一章,将介绍红黑树及其实现,HashMap的remove方法与反树型化.长文预警~~ 遍历HashMap源码--红黑树原理.HashMap红黑树实现与反树型化 什么是红 ...

  7. HashMap底层红黑树原理(超详细图解)+手写红黑树代码

    在看完了小刘老师和黑马的源码视频之后,我整理了一篇HashMap的底层源码文章,学海无涯,这几天看了对红黑树的讲解,故将其整理出来 HashMap底层源码解析上 HashMap底层源码解析下 视频链接 ...

  8. [Java 8 HashMap 详解系列]7.HashMap 中的红黑树原理

    [Java 8 HashMap 详解系列] 文章目录 1.HashMap 的存储数据结构 2.HashMap 中 Key 的 index 是怎样计算的? 3.HashMap 的 put() 方法执行原 ...

  9. 红黑树原理及代码实现(一)

    红黑树简介 红黑树是一种自平衡的二叉查找树,它的统计性能要优于平衡二叉树,因此在很多地方都有应用,例如Java中的TreeMap,HashMap等数据结构都使用到了红黑树.红黑树对很多人来说熟悉而陌生 ...

最新文章

  1. 小而美的个人博客——前端——blog
  2. 斐波那契数列规律的计算。
  3. 青岛理工大学c语言软件,青岛理工大学C语言程序打印版.docx
  4. 高通发布《5G经济》研究:将催生12万亿美元市场
  5. 初中计算机七年级人教版目录,最新人教版初中数学目录(详细)
  6. java计算机毕业设计销售人员绩效管理系统源码+系统+数据库+lw文档(1)
  7. HTTP请求时POST参数到底应该怎么传?
  8. 一个SDK打破实时语音社交的“不可能三角”
  9. Mysql - 开发技巧(二)
  10. java实战小结-Controller报错:Content type ‘multipart/form-data;boundary=----WebKitFormBoundaryxxxx not supp
  11. 关于写作,别那么在意别人的看法,开始干吧
  12. 时隔4年,翟天临怒怼网友:论文写不过是你能力不行...
  13. 设计模式03 行为型模式
  14. 怎么把视频压缩到100MB以内
  15. qlearningα越大或越小_高频电子线路习题及答案
  16. python基础 -23- 模块(random,chardet,os,sys,copy,time,datetime,pytz,pickle,json,MD5,SHA-1,shutil,re等)
  17. The maximum number of apps for free development profiles has been reached.
  18. 数据通信基础 - 信道特性(奈奎斯特定理、香农定理 )
  19. 基于Ubuntu 16.04的HUSTOJ在线判题系统的搭建
  20. 网页素材大宝库:高质量的网站纹理背景素材

热门文章

  1. 微信语音输入不仅仅是懒癌患者的福音
  2. nginx 隐藏版本号
  3. linux手机纠错软件,Linux系统手机——外观/配置/软件评分/平台/基本功能_手机_手机其它OS-中关村在线...
  4. map循环、迭代器使用
  5. [python]bytes型和string型的转换
  6. 组织行为学对项目管理的意义(2):人格的大五模型
  7. 全局变量、静态全局变量、静态局部变量和普通局部变量的区别
  8. Python中少有人回答的问题
  9. 90后普通打工人,如何从零做到5万美金独立站
  10. LeetCode 54.螺旋矩阵 - 原地修改