这是一个好友面试阿里时,被问到的一个问题,应该不少人看到这个问题都会一面懵逼。因为,大部分的文章都是分析链表是怎么转换成红黑树的,但是并没有说明为什么当链表长度为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才转为红黑树相关推荐

  1. map怎么转化dto_阿里面试题:为什么Map桶中个数超过8才转为红黑树

    点击上方"linkoffer", 选择关注公众号高薪职位第一时间送达 这是笔者一个好友面试阿里时,被问及的一个问题,应该不少人看到这个问题都会一面懵逼.因为,大部分的文章都是分析链 ...

  2. map怎么转化dto_阿里面试:为什么Map桶中个数超过8才转为红黑树

    这是一个好友面试阿里时,被问到的一个问题,应该不少人看到这个问题都会一面懵逼.因为,大部分的文章都是分析链表是怎么转换成红黑树的,但是并没有说明为什么当链表长度为8的时候才做转换动作.第一反应也是一样 ...

  3. 为什么Map桶中个数超过8才转为红黑树

    直白一点:就是trade-off,空间和时间上的权衡! 源码中有如下内容: * Because TreeNodes are about twice the size of regular nodes, ...

  4. 【java】为什么HashMap桶中节点个数超过8才转为红黑树?

    纪念一波,九师兄博客热门订阅专栏时常名列前茅,我飘了,哈哈哈哈,得意的笑 1.概述 问题: 为什么HashMap桶中节点个数超过8才转为红黑树? 8这个阈值定义在HashMap中,针对这个成员变量,在 ...

  5. Java多线程学习二十二:为什么 Map 桶中超过 8 个才转为红黑树

    为什么 Map 的桶中超过 8 个才转为红黑树? JDK 1.8 的 HashMap 和 ConcurrentHashMap 都有这样一个特点:最开始的 Map 是空的,因为里面没有任何元素,往里放元 ...

  6. 红黑树实现——STL中的map

    From: http://blog.csdn.net/zhongjiekangping/article/details/6934571 红黑树实现--STL中的map [ 2009-07-24 13: ...

  7. 面试题——轻松搞定面试中的红黑树问题

    版权所有,转载请注明出处,谢谢! http://blog.csdn.net/silangquan/article/details/18655795 连续两次面试都问到了红黑树,关键两次都没有答好,这次 ...

  8. 轻松搞定面试中的红黑树问题

     连续两次面试都问到了红黑树,关键两次都没有答好,这次就完整地来学习整理一下. 没有学习过红黑树的同学请参考: <<Introduction to Algorithms>> ...

  9. 红黑树和平衡二叉树的区别_面试题精选红黑树(c/c++版本)

    红黑树的使用场景非常广泛,比如nginx中用来管理timer.epoll中用红黑树管理事件块(文件描述符).Linux进程调度Completely Fair Scheduler用红黑树管理进程控制块. ...

最新文章

  1. 函数组:SDIFRUNTIME
  2. 用物理学突破深度学习理论瓶颈? Google-斯坦福发布《深度学习统计力学》综述论文,30页pdf阐述深度学习成功机制...
  3. 边缘计算:5G 时代的万亿市场
  4. sublime text3 最新 license注册码分享 2018
  5. createrepo命令安装_安装CDH6.3
  6. 我的征程是未来!带你展望2015年最重要的网页设计趋势
  7. 第六次课作业(质量管理、项目人力资源管理)
  8. 订餐系统-第一个用NodeJs实现的项目
  9. 遗落在时光里的静态链表(线性表的静态存储)---C语言版
  10. 使scp不用输入密码
  11. JAVA视频MP4文件加密,Html5播放器调用
  12. Mac 安装Gradle教程
  13. Jenkins linux 操作系统一键部署多节点
  14. 条件覆盖(Condition coverage)
  15. 在Windows 10下配置 DirectX11 + Visual Studio 2017开发环境
  16. 2017-2018-2 20179216 《网络攻防与实践》 第八周总结
  17. 【启动程序是无法加载 libnsl.so.1】
  18. 从RPA 向 IPA 转型升级!实在智能金秋发布会:重新定义流程自动化
  19. MFC中afx_msg是什么
  20. Excel如何批量调整行高

热门文章

  1. 调幅信号处理实验电路(F 题 本科组)--2017 年全国大学生电子设计竞赛试题
  2. JAVA 获取工作日、节假日工具 Lunar
  3. 艾司博讯:拼多多如何设置客服号
  4. 超分辨入门之SRCNN(小白版)
  5. python爱心代码中间中间加字
  6. SDN 技术指南(一):架构概览
  7. 中创公益|中创算力荣获“2022年度突出贡献爱心企业”
  8. GDevelop 5开发经验分享之 Coriander Games 工作室开发游戏的经验分享
  9. ESXi虚拟机NTP同步
  10. 喜欢书法的程序员看过来:15行代码抓取兰亭序全文单字高清字帖