【老实李】JDK1.8中HashMap的红黑树

作者&投稿:盛宋 (若有异议请与网页底部的电邮联系)
~

上一篇文章 HashMap的底层原理探索 我们分析了JDK1.7中Hashmap的源码实现,但是在JDK1.8的时候HashMap的实现做了很大的变动和优化。1.7和1.7之前HashMap都是“数组+链表”实现的,1.8之后就是“数组+(链表或红黑树)”来实现的了。这里我特地将“链表或红黑树”用一对括号括在一起,因为HashMap底层依旧是一个数组,然后数组中的元素是链表或者红黑树来实现的。

HashMap的实现就先介绍到这,下面就先讲一下红黑树,然后才能理解为什么要用红黑树来优化HashMap,用红黑树有什么好处。

在介绍红黑树之前我们要先理解二叉查找树的数据结构。下面简单介绍一下。

上面这张图就是一个二叉查找树。二叉查找树有如下几条特性

(1).左子树上所有结点的值均小于或等于它的根结点的值。

(2).右子树上所有结点的值均大于或等于它的根结点的值。

(3).左、右子树也分别为二叉排序树

那既然他名字中是有“查找”的,那么他是怎么查找的呢?比如我们要查找10这个元素,查找过程为:首先找到根节点,然后根据二叉查找树的第一二条特性,我们知道要查找的10>9所以是在根节点的右边去查找,找到13,10<13,所以接着在13的左边找,找到11,10<11,继续在11的左边查找,这样就找到了10.这其实就是二分查找的思想。最后我们要查出结果所需的最大次数就是二叉树的高度!(二分查找的思想:找到数组的中间位置的元素v,将数组分成>v和<v两部分,然后将v和要查找的数据进行一个比较,如果大于v那么就在>v的部分再次进行二分查找,否则就在<v的部分进行二分查找,直到找到对应的元素。)

那既然要查出结果所需的最大次数就是二叉树的高度,那这个高度会不会有时候很长呢?

比如我们依次插入 根节点为9如下五个节点:7,6,5,4,3。依照二叉查找树的特性,结果会变成什么样呢?7,6,5,4,3一个比一个小,那么就会成一条直线,也就是成为了线性的查询,时间复杂度变成了O(N)级别。为了解决这种情况,该红黑树出场了。

红黑树其实就是一种 自平衡 的二叉查找树。他这个自平衡的特性就是对HashMap中链表可能会很长做出的优化。

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

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

性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

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

下面这棵树就是一个典型的红黑树

红黑树那么多规则,那么在插入和删除元素会不会破坏红黑树的规则呢?什么情况下会破坏?什么情况下不会?

比如我们向原红黑树插入为14的新节点就不会破坏规则

向原红黑树插入值为21的新节点就破坏了规则

那么红黑树是怎么维护这个二叉查找树的自平衡性的呢?

红黑树通过 “变色”和“旋转” 来维护红黑树的规则,变色就是让黑的变成红的,红的变成黑的,旋转又分为“左旋转”和“右旋转”。这个比较复杂,容易晕,我们就只要知道红黑树就是通过这种方式来实现它的自平衡性就行了。

JDK1.7的时候是使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode相同,或者hashcode取模后的结果相同(hash collision),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。在hashcode特别差的情况下,比方说所有key的hashcode都相同,这个链表可能会很长,那么put/get操作都可能需要遍历这个链表。也就是说时间复杂度在最差情况下会退化到O(n)

红黑树我们大致了解了,他的好处就是他的自平衡性,让他这棵树的最大高度为2log(n+1),n是树的节点数。那么红黑树的复杂度就只有 O(log n)。

下面我们通过追踪JDK1.8 HashMap的put方法的源码来理解

put方法调用了putVal方法

通过putVal方法可以看到这里的数组和1.7不同,是使用了一个Node数组来存储数据。那这个Node和1.7里面的Entry的区别是什么呢?

HashMap中的红黑树节点 采用的是TreeNode 类

TreeNode和Entry都是Node的子类,也就说Node可能是链表结构,也可能是红黑树结构。

如果插入的key的hashcode相同,那么这些key也会被定位到Node数组的同一个格子里。如果同一个格子里的key不超过8个,使用链表结构存储。如果超过了8个,那么会调用treeifyBin函数,将链表转换为红黑树。

先分析到这。。。。。




【老实李】JDK1.8中HashMap的红黑树
JDK1.7的时候是使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode相同,或者hashcode取模后的结果相同(hash collision),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。在hashcode特别差的情况下,比方说所有key的hashcode都相同,这...

jdk兼容问题・_・?
1、为什么要用mac来开发JAVA呢,老实说,苹果的本子用来做设计比较好,做开发不是很方便的说。基本上我的身边的朋友用苹果的本子的,都会装一个windows的系统,因为很多软件在MAC上都不兼容。2、不建议使用其他版本的JDK,不然不兼容是肯定的,除非你们整个项目组都使用那个版本的JDK。这是基础类库,一定...

有关宝鸡的诗句
【第1篇】 家乡是温馨的;家乡是迷人的;家乡是令人自豪的,一说到家乡,我就会滔滔不绝了。 我家乡是宝鸡,古称“陈仓”,是炎帝故里,周秦文化的发祥地,素有“青铜器之乡”,“民间工艺美术之乡”的美称。 到过宝鸡的人一定都会赞叹不已,可你知道曾经的宝鸡是怎样的吗?就拿我局住的地方——清姜东二路来说吧!

五年级下册第22课 人物描写一组 读后感,快哦!好的+分
“于是我把平生所见所闻、所知所得的‘嘎人嘎事’,尽力搜寻,桌上放张纸,想起一点记一点,忆起一条记一条,大嘎子、小嘎子、新嘎子、老嘎子,尽都蹦蹦跳跳,奔涌而至。由于我不喜欢自己的老实刻板,从幼年便把嘎子当做楷模,注意多,观察多,交往多,‘嘎相’储藏也相对较多,尤其抗日时那些嘎不溜丢的小八路们,...

成语故事内容30字
链接: https:\/\/pan.baidu.com\/s\/1ap2nrjqOeduGrIGwvNs23A 提取码: 29uq 复制这段内容后打开百度网盘手机App,操作更方便哦 成语故事

澧县13748633880: 在JDK1.8中,是不是对HashMap的实现方式进行了大的改变,putall方法好像跟以前也不一样了? -
弋腾五氟: 在JDK1.8中,对HashMap的存储结构有链表改成了平衡树,当通过key去获取entity时,复杂度由O(n)降低到了O(log n),性能提供了不少,建议升级.

澧县13748633880: java中,HashMap底层数据结构是什么? -
弋腾五氟: jdk1.8以前是数组+连表,jdk1.8以后是数组+连表+红黑树,数组长度超过8会变成红黑树,小于8依然是数组+连表

澧县13748633880: jdk1.8hashmap有什么改动吗引入红黑树 -
弋腾五氟: JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布.当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势.针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题.

澧县13748633880: HashMap的底层实现以及ConcurrentHashMap的底层实现 -
弋腾五氟: 这是javase 的底层基础.不管是 前者还是后者 都要分不同版本的jdk来进行区分.大体上来说hashMap 是非线程安全的,底层实现是数组链表.但jdk1.8版本的实现方式就是数组链表+红黑树.这点可以再度娘中查到.后者是现成安全的.但也要区分jdk版本.手不能懒

澧县13748633880: jdk1.8 tomcat配哪个版本 -
弋腾五氟: 1. 从master开始建立自己的jruby. 2. 从oracle下载openjdk 7. 3. 在新的jdk中指向java_home,开始试用jruby.

澧县13748633880: jdk1.8环境变量设置,越详细越好 -
弋腾五氟: 设置jdk 1.8环境变量的步骤如下: 1.设置JAVA_HOME:在“系统变量”中,点击“新建”,变量名填写:JAVA_HOME,变量值填写:C:\Program Files\Java\jdk1.8.0_31(即安装的jdk的目录) 2.设置path:在系统变量的上方的“用户变量”中,点击“新建”,变量名填写:path(不区分大小写),变量值填写:%JAVA_HOME%\bin3设置class path:在系统变量的上方的“用户变量”中,点击“新建”,变量名填写:class path(中间有空格,不区分大小写),变量值填写:%JAVA_HOME%\lib

澧县13748633880: jdk 1.8 foreach怎么循环map -
弋腾五氟: hashmap b=new hashmap() for(object a:b)〔 sys……(a) 〕

澧县13748633880: 1.8版本的JDK中,hashset存和取的顺序是否一致?或者说存储顺序是否有序? -
弋腾五氟: 无序的,hashset的底层其实是基于hashmap的,存储顺序是基于hash码,无法保证存储顺序

澧县13748633880: jdk 1.8 api chm 怎么打开 -
弋腾五氟: 在地图上显示计划事件,jQuery UI Map会集成Google地图,从而让开发者轻而易举地创建交互式地图.jQuery UI Map最大的特点就是,当客户端不支持JavaScript时,开发者可以在备用站点上使用微格式、RDFa或微数据等HTML数据格式实现同步.

澧县13748633880: linux下怎样安装jdk1.8? -
弋腾五氟: 方法/步骤 第一步:下载Linux环境下的jdk1.8,请去(官网)中下载jdk的安装文件;第二步:新建/usr/java文件夹,将jdk-8u25-linux-i586.tar.gz放到该文件夹中,并将工作目录切换到/usr/java目录下.第三步:通过以上步骤,jdk1.8就已...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网