【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

时间:2022-09-03 17:09:37

Style:Mac

Series:Java

Since:2018-09-10

End:2018-09-10

Total Hours:1

Degree Of Diffculty:5

Degree Of Mastery:5

Practical Level:5

Desired Goal:5

Archieve Goal:3

Gerneral Evaluation:3

Writer:kingdelee

Related Links:

http://www.cnblogs.com/kingdelee/

https://www.jianshu.com/p/65c90aa1236d

https://www.cnblogs.com/zhangbaochong/p/5164994.html

http://www.cnblogs.com/skywang12345/p/3577479.html

https://blog.csdn.net/qq_25806863/article/details/74755131

https://blog.csdn.net/skyroben/article/details/72824146

1.在put的时候,当节点数>=7时,会执行进化树结构,调用treeifyBin(tab, hash)

for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
logger.info("p.next为空,为其创建新的节点,p.next.hash:" + hash + ", p.next.value:" + value);
p.next = newNode(hash, key, value, null); // 将当前的节点的下一个节点指向新创建的节点
if (binCount >= TREEIFY_THRESHOLD - 1) // 只有>=7次迭代才会执行进化树结构
{
logger.info("binCount >= (TREEIFY_THRESHOLD - 1), binCount:" + binCount + ", (TREEIFY_THRESHOLD - 1):" + (TREEIFY_THRESHOLD - 1));
treeifyBin(tab, hash);
}
logger.info("跳出循环");
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))){
logger.info("同一个对象");
break;
}
logger.info("p.next有值, p.next.hash:" + p.next.hash + ",p.next.value:" + p.next.value + ", 把当前p指针指向p.next");
p = e;
}

  

2. 每次在同坑位的节点>=7的情况下,但凡put节点进来都会进行一次扩容

所以,在容量小于64时,在当同坑位的节点>=7,每递增一个节点,进行一次扩容

当容量大于64时,进化树结构。

final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
logger.info("n = tab.length:" + tab.length);
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) //小于最小默认树结构容量64时进行扩容
{
logger.info("小于树最小容量阀值64,进行扩容");
resize();
}
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}

  

3.说说树

为毛要用树这种结构?

原理引用:1.有序数组虽然查询快插入慢,而链表插入快但是查询慢;

而树的查找效率如下,层数是遍历次数,时间复杂度 O(logN)

以下源自《Java数据结构和算法(第二版)》

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

红黑树

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

必须满足4个规则:

1.每一个节点不是红色就是黑色

2.根总是黑色

3.若节点时红色,则其子节点一定是黑

4.从根到叶节点或非空子节点的每条路径,必须包含相同数量的黑色节点

5.每个叶节点(NIL,即正常情况下的最后一个节点的1个或2个隐式节点)都是黑的

3.AVL

平衡检测

高度(height):从根节点(root)开始到某一个叶子节点(leaf)的最长路径(path)上结点的个数

平衡因子(balanced factor):某个结点的平衡因子等于该节点的左孩子的高度减去右孩子的高度

根据平衡树的定义,计算得到的平衡因为会出现两种情况:

  • 如果平衡因子是01-1 这三个数的话,可以认定该节点是符合平衡树的定义的;
  • 否则,该结点不平衡,需要重新平衡;
对于一个BST来说,每次插入的元素只可能放在叶子结点上。所以只能影响某个子树是否平衡,对其他子树不会有任何的影响。在这种情况下,我们只需要根据搜索的路径,从孩子往祖先找,如果有不平衡的结点就可以被找到。如果一直到根结点都没有发现不平衡结点,则可以认为这次的插入操作没有造成树的不平衡。

重平衡

如果发现了某个不平衡的结点,那么就需要对该结点进行重平衡。实现重平衡的方法,是对该节点的子树进行旋转(rotation)。

把需要重新平衡的结点叫做α,由于任意两个结点最多只有两个儿子,因此高度不平衡时,α结点的两颗子树的高度相差2.容易看出,这种不平衡可能出现在下面4中情况中:

1.对α的左儿子的左子树进行一次插入

2.对α的左儿子的右子树进行一次插入

3.对α的右儿子的左子树进行一次插入

4.对α的右儿子的右子树进行一次插入

举例:

1.最初的AVL

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

50先插入,50为根;再插入的20比50小,故应插入50左下,作为50的左子树;再插入的80比50大,故应插入50的右下,作为50的右子树;

插入10,比50小,左下,比20小,左下;插入40,比50小,左下,比20大,右下;

故,这图为,50为根,50的左子树是以20为根的子树(20,10,40....),50的右子树以80为根的子树

50的左子树长度是20->10,即2;右子树长度为1;2-1=1,符合平衡树的差值;这是一个AVL树

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

此时,倘若只要左子树再增加一个长度(即插入诸如2,12,30,45等)

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

50的左子树的长度变为3,而右子树的长度为1,差值为2而不是小于等于1,此时,不符合AVL树的要求。

故在AVL的规范下,需要对此时的非AVL做调整形成AVL树

对其中(添加2或12)此种,左子树(20->10>2或20->40->30)比右子树(80)的路径>1,且是在最后一层(10, 40)的左边,称为:LL左左

对其中(添加30或45)此种,左子树(20->40>30或20->40->45)比右子树(80)的路径>1,且是在最后一层(10, 40)的右边,称为:LL左右

对于LL左左的旋转操作:

左旋:操作如下图【最好用谁强大谁上位来理解,否则用旋转理解,谁旋谁死;见过有硬硬解释旋转的,还用通过逆顺时针来解释的,勉强多看几次是能看懂但不好理解会忘;绝无仅有,申请专利,将xx旋转更名为Lee上位:)】

白话左旋就是,50根失去左平衡,受不了左边20的压力就断开与左20的连接;20成功上位,但是不能不管曾经的老大根,所以,把旧老大作为自己的右小弟(右子树);只能有一个右小弟呐,新老大20认为旧老大50好歹也做过老大经验丰富,就把自己的小弟40丢给旧老大50左他的小弟。完。左旋一点都不好理解,应理解为哪边失衡(变强大),哪边就要上位了。

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

所以ll左左如下,左左是其他变形的基础,其他都是变形的理解都是建立在这个东西之上的。

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

------------------------------------

对于LR左右:

我们采取和之前上位一样的操作

50的左子树失衡,断开与20的连接;20上位,右边重连50,把40丢给50持有。

发现仍失衡

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

为毛在10底下的新节点就行,为在40底下的新节点就不行?啊咧,仅有这样的区别的话,想办法形成和之前的最初的左左的图一样不就可以了吗

于是:

20上位行不通,40上位试一试。

第一次上位:验算中发现20太弱尝试做老大是失败的(这一步不需要实操),20的小弟40要上位;20断开与50的连接,40上位20;40与50产生连接成为新的小王;20被40收容做小弟。可是仍没平衡呐,但是出现LL形状了,胜利就在眼前,40可以采取LL的方式继续上位

第二次上位:和LL一样,40断开与50的连接上位,50成为40的小弟;40把自己的小弟45丢给前老大50收容,AVL了

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

以上解决了LL和LR两种图形

结论是:

1.当发现新加入的节点造成根出现左子树失衡,且新加入的节点是在叶节点(最后一层)的左节点上,即为LL;老二上位1次即可

2.当发现新加入的节点造成根出现左子树失衡,且新加入的节点是在叶节点(最后一层)的右节点上,即为LR;老三上位2次即可

----------------------------------------------------

如果AVL是这样子的,插入以下新的节点都会导致AVL失衡,和上面很像了

同理,1、2是RL,3、4是RR

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

先看3、4的RR,这个是基础

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

RL呢

跟之前是类似的

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

可是,以上仍然不够严谨

因为

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

两种都能够保持AVL,但是哪种才是正确的呢

结论是:8上位。

直观理由:1.这样变动更少,2.更安全.3.最近原则

问题来了:没法总是看图,如何用代码表示呢

引用了所谓的平衡因子c

重新看一下LL:

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

看一下LR

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

RR RL依据之前没给出深度值的加上深度值就可以了

【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】的更多相关文章

  1. 【JVM】-NO&period;110&period;JVM&period;1 -【JDK11 HashMap详解】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  2. 【JVM】-NO&period;113&period;JVM&period;1 -【JDK11 HashMap详解-0-全局-put】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  3. 【JVM】-NO&period;113&period;JVM&period;1 -【JDK11 HashMap详解-4-resize&lpar;&rpar;】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  4. 【JVM】-NO&period;115&period;JVM&period;1 -【JDK11 HashMap详解-4-伸展树、B树】

    .Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  5. 【JVM】-NO&period;116&period;JVM&period;1 -【JDK11 HashMap详解-5-红黑树】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  6. 【JVM】-NO&period;111&period;JVM&period;1 -【JDK11 HashMap详解-1-hash&lpar;&rpar;剖析】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  7. 【JVM】-NO&period;112&period;JVM&period;2 -【JDK11 HashMap详解-2-tab&lbrack;i &equals; &lpar;n - 1&rpar; &amp&semi; hash&rsqb;&rpar;剖析】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  8. java面试题之----JVM架构和GC垃圾回收机制详解

    JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...

  9. 【转】 java中HashMap详解

    原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...

随机推荐

  1. IIS7&period;0上传文件限制的解决方法

    在 Windows7(iis7.5).Win2008(iis 7.0)和Win2003(iis 6.0) 中,默认设置是特别严格和安全的,这样可以最大限度地减少因以前太宽松的超时和限制而造成的攻击. ...

  2. jquery 使用attr&lpar;&rpar; 函数对复选框无效的原因&comma;javascript那些事儿&mdash&semi;&mdash&semi;properties和attributes

    复选框是网站开发的时候经常用到的网页标签之一,常见的在页面上对复选框的操作包括取值和修改复选框的状态.在jquery中,常见的操作标签的值得函数为attr,然而在操作复选框的时候,通常采用的却是pro ...

  3. Unity3D脚本中文系列教程&lpar;三&rpar;

    http://dong2008hong.blog.163.com/blog/static/4696882720140302323886/ Unity3D脚本中文系列教程(二) 示,属性不被序列化或显示 ...

  4. 学习笔记&lowbar;Java get和post区别(转载&lowbar;GET一般用于获取&sol;查询资源信息,而POST一般用于更新资源信息&rpar;

    转载自:[hyddd(http://www.cnblogs.com/hyddd/)] 总结一下,      Get是向服务器发索取数据的一种请求      而Post是向服务器提交数据的一种请求,在F ...

  5. Zepto源码笔记(三)

    ps:本文中"组装成成数组"指的是若元素个数大于1则返回数组,若元素只有1个则返回元素本身 以下函数是$.fn该对象的方法 ready(callback) 通过readyRE正则表 ...

  6. PHP 超强过滤函数

    PHP 超强过滤函数 你有每次要过滤的时候总是去翻曾经的过滤代码的时候么? 你有搜索过怎样防过滤,防攻击的PHP解决方法么? 你有对全然遵循'过滤输入,避免输出',Web界经典说辞么?     事实上 ...

  7. VMware安装CentOS 提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案

    安装虚拟机遇到错误: 在网上查了查资料,发现CPU支持VT技术的就能支持vmware中安装64位虚拟机. 以下是操作步骤: 1)到网上下载一个securable.exe,测试以下机器是否支持VT. l ...

  8. spring boot &plus; vue &plus; element-ui全栈开发入门——前端列表页面开发

     一.页面 1.布局 假设,我们要开发一个会员列表的页面. 首先,添加vue页面文件“src\pages\Member.vue” 参照文档http://element.eleme.io/#/zh-CN ...

  9. Dynamic CRM 2015学习笔记(6)没有足够的权限 - 您没有访问这些记录的权限。请联系 Microsoft Dynamics CRM 管理员

    我们经常遇到下面这种问题:没有足够的权限 - 您没有访问这些记录的权限.请联系 Microsoft Dynamics CRM 管理员.  下面将详细介绍下如何解决这种问题:进不了CRM系统:进了CRM ...

  10. http协议以及get和post请求

    HTTP协议是网络传输信息的一种规范. 就好比两个人之间的交流,甲只会讲英语,乙只会说汉语,结果是他们必然无法开怀畅谈. HTTP协议也类   GET 请求获取 Request-URI 所标识的资源 ...