HashMap源码验证,在JDK8中新增红黑树详解

红黑树查询演示,红黑树它解决了链表查询过慢的问题

我们插入的链表过长之后,因为我们的链表都是从头部开始进行查询,所以它会比较慢。

我们现在引入到我们的红黑树之后呢,它就不会有这个问题,那它是怎么去解决呢?

我们来看一看,刚才我们还是去插入这7个元素

我们一个红黑树的,它的一个结构呢,就七个节点的元素是这样的,

来我们看一下,我们用红黑树去查这个007要查多少次呢?
https://img1.tuicool.com/BzeIB3m.gif
一次,两次,三次,四次,

也就是说我们用红黑树啊,只要查四次,而刚才我这个用链表是要查七次,

那我是不是减少了三次的这个查询次数,那同时我们就非常的明显,

如果我们这边是70万,这边只要查40万,那我就减少了30万的查询,

那这样的话是不是性能将近提高了一倍,能理解吧,

所以我们这个红黑树,它就是去解决我们链表查询过慢的一个问题。

在JDK8里面,HashMap并不是一上来就直接用这个红黑树

但是呢,我们这个HashMap,在JDK8里面,它并不是一上来就直接用这个红黑树,

一上来它默认还是先用链表, 只有当我们的这个链表达到一个阈值的情况下,

它才会用这个红黑树,那你们知道这个阈值是多少吗?

阈值是8,那同学们我想问一下,为什么是8呢?

看HashMap源码

咱们看这个HashMap的一个源码,Shift+Shift,搜索HashMap,

同时勾选 Include non-project items,如下图


在这个地方,HashMap呢,我们主要看它的这个put方法,它调用了 putVal方法,


那这个 putVal 方法里面呢,它有一个值,这个条件它就等于8,



那为什么我们的链表的长度大于8之后呢,就会用红黑树,

如果不大于8的话,它是用链表,大家你们知道为什么吗?

来,其实在这里,它也不是等于8,严格意义上它是用8减1,

<pre class="hljs awk" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 

大家看它的条件,你看如果这个条件满足情况,它就调这个方法 treeifyBin,

if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

treeifyBin (tab, hash);

break;

treeifyBin 这个方法,


你看一上来的话,它这里是用什么?这里是用的是咱们这个链表,

你看里面有 hash(哈希),有 key 和 value,next 对吧?开始用链表,


但是当我们这个条件执行 else if 的时候,他用这个 TreeNode,


而这个 TreeNode 就是咱们这个红黑树,你看里面,还有 boolean 类型是否为红节点,

我们的上一个节点、右节点、左节点,还有我们的根节点,


为什么红黑树查询快,插入慢?

为什么红黑树,它的查询性能就一定会比咱们的这个链表快呢?

第一个就取决于它这个查询的规律不一样对吧!

那么我想问一下,那为什么就一定要有一个阈值?为什么还要先要用链表的?

那为什么一上来不直接用红黑树呢?原因是什么?

而且我们明明已经知道链表,它已经会带来这个查询的这个慢的原因

我们要知其然知其所以然,那么这个东西呢,其实就是鱼和熊掌不可兼得,

那我来跟大家去讲一下,刚刚在这个地方,我是讲的是红黑素这个查询,但是同学们,

我来给大家看一下它的插入,它的插入你来认真去看这个节点,你就明白了!

来我把这个东西给你再演示一遍

https://img1.tuicool.com/BzeIB3m.gif
你们注意看啊,插入第一个,插入第二个

好,当我去插第三个值的时候,你们注意看啊,看到没有,

我们的这个001,它进行了一次左移(左旋)。

也就是说我们的红黑树,它的查询是比较快,但是它的插入比较慢,为什么呢?

因为它需要对我们的值进行左移,进行左移(左旋)的话,他们的数据是进行需要进行交换的,

所以在这个过程中,我可以很负责任的告诉大家,我们的这个插入,

我们的链表绝对会比我们的红黑树要更快一些。

所以我们来看一看链表它的特性是什么?它的特性是插入删除会比较快,

因为它只要O(1)的操作,而咱们这个红黑树很明显不是O(1)的操作,

所以这就是为什么需要有一个阈值,这个阈值就是使得它们两者达到一个平衡。

这就是鱼和熊掌不可兼得!


那在这里我就跟大家讲,为什么我们的红黑树,它查询为什么会快呢?原因你们知道为什么吗?

因为我们的红黑树,它需要维护一个结构,维护一个什么样的结构呢?

我把这个技巧告诉大家,这个技巧就是:小中大,左中右

那这个是一个什么样的一个结构呢?

那大家我们来看啊,当前我这个红黑树数的一个节点,根节点是002,

我们要去查询的这个值是007,而比002小的是不是001。

你看比它002小的,是不是在左边,比002大的,你看003、004、005、006、007都在右边,

大家能理解这个点吗?这就是小中大,左中右这个结构,

你任何一个节点的数据都是这样的。

来我们来看004啊,你看004也是一样,比004小的,都在左边,

你看001、002、003是不是都在左边。

比004大的,是不是在右边,你看005、006、007。

同样,006也是一样,这就是小中大,左中右这个结构,

如果你能理解这个点,那你就明白了,所以为什么我们的红黑素在插入的时候会慢,

因为它要维护这样的一个结构,它要维护一个小中大,左中右的一个结构,

所以我们为什么查007的话,为什么快?

因为我们首先呢,007跟002进行比较对吧,所以发现这个007大

就这样,007依次会002、004、006、007 进行比较,直到找到相等的007

#java##程序员#
全部评论
详细讲解的全过程
点赞 回复 分享
发布于 2022-08-31 11:33 河南

相关推荐

点赞 评论 收藏
分享
点赞 4 评论
分享
牛客网
牛客企业服务