精选(1)为什么Map桶中个数超过8才转为红黑树
这是一个好友面试阿里时,被问到的一个问题,应该不少人看到这个问题都会一面懵逼。因为,大部分的文章都是分析链表是怎么转换成红黑树的,但是并没有说明为什么当链表长度为8的时候才做转换动作。第一反应也是一样,只能初略的猜测是因为时间和空间的权衡。
要弄明白这个问题,首先要明白为什么要转换,这个问题比较简单,因为Map中桶的元素初始化是链表保存的,其查找性能是O(n),而树结构能将查找性能提升到O(log(n))。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。至于为什么阈值是8,我想,去源码中找寻答案应该是最可靠的途径。
8这个阈值定义在HashMap中,如下所示,这段注释只说明了8是bin(bin就是bucket,即HashMap中hashCode值一样的元素保存的地方)从链表转成树的阈值,但是并没有说明为什么是8:
** * The bin count threshold for using a tree rather than list for a * bin. Bins are converted to trees when adding an element to a * bin with at least this many nodes. The value must be greater * than 2 and should be at least 8 to mesh with assumptions in * tree removal about conversion back to plain bins upon shrinkage. */static final int TREEIFY_THRESHOLD = 8;
我们继续往下看,在HashMap中有一段 Implementationnotes
,笔者摘录了几段重要的描述,第一段如下所示,大概含义是当bin变得很大的时候,就会被转换成TreeNodes中的bin,其结构和TreeMap相似,也就是红黑树:
This map usually acts as a binned (bucketed) hash table, butwhen bins get too large, they are transformed into bins of TreeNodes,each structured similarly to those in java.util.TreeMap
继续往下看,TreeNodes占用空间是普通Nodes的两倍,所以只有当bin包含足够多的节点时才会转成TreeNodes,而是否足够多就是由TREEIFY_THRESHOLD的值决定的。当bin中节点数变少时,又会转成普通的bin。并且我们查看源码的时候发现,链表长度达到8就转成红黑树,当长度降到6就转成普通bin。
这样就解析了为什么不是一开始就将其转换为TreeNodes,而是需要一定节点数才转为TreeNodes,说白了就是trade-off,空间和时间的权衡:
Because TreeNodes are about twice the size of regular nodes, weuse them only when bins contain enough nodes to warrant use(see TREEIFY_THRESHOLD). And when they become too small (due toremoval or resizing) they are converted back to plain bins. Inusages with well-distributed user hashCodes, tree bins arerarely used. Ideally, under random hashCodes, the frequency ofnodes in bins follows a Poisson distribution(http://en.wikipedia.org/wiki/Poisson_distribution) with aparameter of about 0.5 on average for the default resizingthreshold of 0.75, although with a large variance because ofresizing granularity. Ignoring variance, the expectedoccurrences of list size k are (exp(-0.5)*pow(0.5, k)/factorial(k)). The first values are:0: 0.606530661: 0.303265332: 0.075816333: 0.012636064: 0.001579525: 0.000157956: 0.000013167: 0.000000948: 0.00000006more: less than 1 in ten million
这段内容还说到:当hashCode离散性很好的时候,树型bin用到的概率非常小,因为数据均匀分布在每个bin中,几乎不会有bin中链表长度会达到阈值。但是在随机hashCode下,离散性可能会变差,然而JDK又不能阻止用户实现这种不好的hash算法,因此就可能导致不均匀的数据分布。不过理想情况下随机hashCode算法下所有bin中节点的分布频率会遵循泊松分布,我们可以看到,一个bin中链表长度达到8个元素的概率为0.00000006,几乎是不可能事件。所以,之所以选择8,不是拍拍屁股决定的,而是根据概率统计决定的。由此可见,发展30年的Java每一项改动和优化都是非常严谨和科学的。
- 画外音
通过搜索引擎搜索这个问题,发现很多下面这个答案(猜测也是相互转发):
红黑树的平均查找长度是log(n),如果长度为8,平均查找长度为log(8)=3,链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,这才有转换成树的必要;链表长度如果是小于等于6,6/2=3,而log(6)=2.6,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
认为这个答案不够严谨:3相比4有转换的必要,而2.6相比3就没有转换的必要?起码我不敢苟同这个观点。
精选(1)为什么Map桶中个数超过8才转为红黑树相关推荐
- map怎么转化dto_阿里面试题:为什么Map桶中个数超过8才转为红黑树
点击上方"linkoffer", 选择关注公众号高薪职位第一时间送达 这是笔者一个好友面试阿里时,被问及的一个问题,应该不少人看到这个问题都会一面懵逼.因为,大部分的文章都是分析链 ...
- map怎么转化dto_阿里面试:为什么Map桶中个数超过8才转为红黑树
这是一个好友面试阿里时,被问到的一个问题,应该不少人看到这个问题都会一面懵逼.因为,大部分的文章都是分析链表是怎么转换成红黑树的,但是并没有说明为什么当链表长度为8的时候才做转换动作.第一反应也是一样 ...
- 为什么Map桶中个数超过8才转为红黑树
直白一点:就是trade-off,空间和时间上的权衡! 源码中有如下内容: * Because TreeNodes are about twice the size of regular nodes, ...
- 【java】为什么HashMap桶中节点个数超过8才转为红黑树?
纪念一波,九师兄博客热门订阅专栏时常名列前茅,我飘了,哈哈哈哈,得意的笑 1.概述 问题: 为什么HashMap桶中节点个数超过8才转为红黑树? 8这个阈值定义在HashMap中,针对这个成员变量,在 ...
- Java多线程学习二十二:为什么 Map 桶中超过 8 个才转为红黑树
为什么 Map 的桶中超过 8 个才转为红黑树? JDK 1.8 的 HashMap 和 ConcurrentHashMap 都有这样一个特点:最开始的 Map 是空的,因为里面没有任何元素,往里放元 ...
- 红黑树实现——STL中的map
From: http://blog.csdn.net/zhongjiekangping/article/details/6934571 红黑树实现--STL中的map [ 2009-07-24 13: ...
- 面试题——轻松搞定面试中的红黑树问题
版权所有,转载请注明出处,谢谢! http://blog.csdn.net/silangquan/article/details/18655795 连续两次面试都问到了红黑树,关键两次都没有答好,这次 ...
- 轻松搞定面试中的红黑树问题
连续两次面试都问到了红黑树,关键两次都没有答好,这次就完整地来学习整理一下. 没有学习过红黑树的同学请参考: <<Introduction to Algorithms>> ...
- 红黑树和平衡二叉树的区别_面试题精选红黑树(c/c++版本)
红黑树的使用场景非常广泛,比如nginx中用来管理timer.epoll中用红黑树管理事件块(文件描述符).Linux进程调度Completely Fair Scheduler用红黑树管理进程控制块. ...
最新文章
- 函数组:SDIFRUNTIME
- 用物理学突破深度学习理论瓶颈? Google-斯坦福发布《深度学习统计力学》综述论文,30页pdf阐述深度学习成功机制...
- 边缘计算:5G 时代的万亿市场
- sublime text3 最新 license注册码分享 2018
- createrepo命令安装_安装CDH6.3
- 我的征程是未来!带你展望2015年最重要的网页设计趋势
- 第六次课作业(质量管理、项目人力资源管理)
- 订餐系统-第一个用NodeJs实现的项目
- 遗落在时光里的静态链表(线性表的静态存储)---C语言版
- 使scp不用输入密码
- JAVA视频MP4文件加密,Html5播放器调用
- Mac 安装Gradle教程
- Jenkins linux 操作系统一键部署多节点
- 条件覆盖(Condition coverage)
- 在Windows 10下配置 DirectX11 + Visual Studio 2017开发环境
- 2017-2018-2 20179216 《网络攻防与实践》 第八周总结
- 【启动程序是无法加载 libnsl.so.1】
- 从RPA 向 IPA 转型升级!实在智能金秋发布会:重新定义流程自动化
- MFC中afx_msg是什么
- Excel如何批量调整行高