前言

JDK8中对HashMap做了优化,依然是用数组存储数据,但是扩容时采用双链表的方式避免了高并发情况下导致出现循环链表的问题,另外也引入了红黑树,提高碰撞元素的搜索速度。

一段代码

下面这段代码创建一个容量为64的HashMap和插入一些数据。

HashMap<Integer,Integer> hashMap=new HashMap<>(64);
hashMap.put(5,5);
hashMap.put(2,2);
hashMap.put(69,69);
hashMap.put(66,66);
hashMap.put(325,325);
hashMap.put(197,197);
hashMap.put(261,261);
hashMap.put(133,133);
hashMap.put(389,389);
hashMap.put(453,453);
hashMap.put(133,999);

如何定位数据下标

一开始说到HashMap是用数组来存储数据,那么数组下标和key是怎么关联上的呢。其实它是将key的hash值和数组长度进行一系列的位运算(异或和与)得出数据下标。例如key=69时,运算如下

最后得出下标是5,那就把(69,69)包装成Node<Integer,Integer>放在数组5的位置上。

链表

从上面公式可以看到,大小相差64的key计算出来的位置都是一样的,例如5和69计算出来的下标都是5,产生冲突了。数组一个下标只能存储一个元素,那么怎么办。HashMap这个时候会用链表来存储冲突的元素,第一个存储在数组的就是链表头Node,接下来冲突元素放在链表头Node的Next位置上,上面那段代码执行流程如下:

从上面的动图可以看到,每个元素都是链表顺序往下找,如果找到相同key的元素,就替换value,否者就放在链表的尾元素的next上。那么问题来了,如果链表很长,每次都要一直遍历到尾部,这太耗时了,时间复杂度为O(n)。如果将链表改成红黑树,那么时间复杂度将会是O(logn)。事实上,HashMap就是这么干的。

红黑树

在HashMap中,当链表长度大于8时,链表将会转成红黑树。而红黑树的根会存储在数组中。如果这个时候再put一个元素(517,517),将会触发树转换,最终转换的结果如下

在说转换之前,可以先来了解一下红黑树的概念。其实红黑树是近似二叉平衡树的,二叉平衡树又是二叉树的一种,他们之间的关系如下

我个人觉得从二叉搜索树开始,在计算机科学中才有一定价值。每一种树都有性质,性质是继承的,越里面的树性质越多。

  • 二叉搜索树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
  • 平衡二叉搜索树:在二叉树的基础上,加上性质:它的左右两个子树的高度差的绝对值不超过1。平衡二叉搜索树搜索复杂度总是O(logn),有效规避了有序元素插入的情况导致退化成链表的问题。
  • 红黑树:在二叉搜索树的基础上,加入四个性质,使树总是保持近似平衡,搜索时间复杂度也是O(logn)。

1. 节点是红色或黑色。

2. 根节点是黑色。

             3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
             4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
      红黑树是通过一定算法来满足上面四个性质,以达到一种近似平衡的状态。与其说算法,不如说公式吧。玩过魔方的都知道,要还原只需要根据几个公式不断地旋转,到最后就不知不觉还原了。其实红黑树也差不多,每插入一个新的元素都可能破坏红黑树的性质,这个时候红黑树会根据几个公式来还原。它们分别为变色,左旋和右旋。通常情况下,几个公式都是组合使用的。
      现在回到刚才转换的话题。首先HashMap会将链表转成树节点的链表,然后根据链表顺序,一个个元素插入到红黑树中,每插入一个元素,都做一次树平衡的调整,理论上最多调整3次,调整流程如下:

按照红黑树的性质,每次新插入的都是在树的最下面,为红叶子,因为红叶子可能都不用调整,黑叶子100%要调整。从上面的流程图可以看到,调整都是从新增的红叶子开始的,通过变色或者左旋右旋的操作不断向上调整,直到调整到根节点。

HashMap三两事的更多相关文章

  1. [转]关于AS3 Socket和TCP不得不说的三两事

    磨刀不误砍柴工,让我们从概念入手,逐步深入. 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络 ...

  2. Spring配置之标签的三两事

    今天看到项目的配置,看后就当是复习了.懵懵懂懂工作两年,感觉虽然自己一直在使用spring作为工具,但是也没有涉及到spring的方方面面,今天的研究从一次无意的自动补全开始,还是那句话,不爱研究的程 ...

  3. vue打包之部署在非根路径下的三两事

    首先,感叹一下,2019年已经过去一半,想想自己做了些什么,好像也没做什么. 今天试着配一个nginx,以前的nginx都是指向的/根路径,今天的nginx指向的非/根路径,遇到许多问题的,总结总结. ...

  4. C++:MEMSET的大坑三两事

    之前写了一题费用流,竟然硬是在写SPFA时为DIS数组赋初始值用了MEMSET数组QAQ 调试了很久也没有弄明白自己是卡在那里了,,,感觉被自己蠢哭了QWQ 错误的姿势!! #include < ...

  5. nodejs之mock与跨域代理的三两事

    emmm...好久没写博客了,都忘了该怎么开始. 那就先说下mockjs.因为一些原因,导致后台接口没有数据,那么我们就开始自己造数据,使用的是比较流行mockjs,根据文档就能简单的配置,然后开始愉 ...

  6. iad 集成三两事

    1. 好像是随着ios8的beta开始.  iad 已经发生了一些变化. 比如找不到enable iad network 的按钮了. 貌似是不需要手动去 enable 了. 只需要嵌入 iad fra ...

  7. 微信小程序:开发之前要知道的三件事

    前言 微信之父张小龙在年初的那次演讲中曾表示:"我自己是很多年的程序员,我觉得我们应该为开发的团队做一些事情".几个月后,微信正式推出微信应用号(即微信小程序),在互联网中掀起了又 ...

  8. <转>离婚前夜悟出的三件事

    文/铁眼(简书作者)原文链接:http://www.jianshu.com/p/832be4f659a0?utm_campaign=hugo&utm_medium=reader_share&a ...

  9. day16模块,导入模板完成的三件事,起别名,模块的分类,模块的加载顺序,环境变量,from...import语法导入,from...import *,链式导入,循环导入

    复习 ''' 1.生成器中的send方法 -- 给当前停止的yield发生信息 -- 内部调用__next__()取到下一个yield的返回值 2.递归:函数的(直接,间接)自调用 -- 回溯 与 递 ...

随机推荐

  1. 公众平台第三方平台 .NET开发

    前言:本博客借鉴了很多三方内容整理的,参考博客:竹叶苿. 一.开发的目的(以下是引用官方的话) 公众平台第三方平台 是为了让公众号或小程序运营者,在面向垂直行业需求时,可以一键授权给第三方平台(并且可 ...

  2. 阿里云 elasticsearch 增删改查

    kibana 控制台 # 查询所有数据 GET /yixiurds_dev/_search { "query": { "match_all": { } } } ...

  3. OGG学习笔记02

    实验环境:源端:192.168.1.30,Oracle 10.2.0.5 单实例目标端:192.168.1.31,Oracle 10.2.0.5 单实例 1.模拟源数据库业务持续运行 2.配置OGG前 ...

  4. windows下修改vagrant虚拟机中的html ,通过nginx访问后不生效

    更改本地html文件,通过nginx配置的虚拟域名访问, 无论怎么修改内容,都不变化,即使我把内容删除一半,它显示的也是以前内容的一半,除非删除文件,才会从新生成. 解决办法 修改nginx.conf ...

  5. Linux下的打包操作

    范例一:将整个 test 目录下的文件全部打包成为 test.tar[python@master ~]$ tar -cvf test.tar test/         ==仅打包,不压缩!test/ ...

  6. Java并发与多线程

    1. 并发与并行 并发是指某个时间段内,多任务交替处理的能力:并行是指同时处理多任务的能力,多核CPU可以实现并行任务. 并发执行的特点: (1)并发程序间相互制约:程序执行结果的相互依赖以及共享资源 ...

  7. conda创建和使用python的虚拟环境

    https://uoa-eresearch.github.io/eresearch-cookbook/recipe/2014/11/20/conda/ 当我们使用服务器的时候,会存在多个用户,并且可能 ...

  8. Java运行环境绿色部署配置

    这个Java的绿色安装配置,还有从未自己的使用电脑说起来. 最近电脑运行慢,很长时间没有清理及维护了,而且有可能中毒或木马了,所以就把系统进行了Ghost还原了,所以原来安装的jdk环境也无法使用了, ...

  9. Trie树(代码),后缀树(代码)

    Trie树系列 Trie字典树 压缩的Trie 后缀树Suffix tree 后缀树--ukkonen算法 Trie是通过对字符串进行预先处理,达到加快搜索速度的算法.即把文本中的字符串转换为树结构, ...

  10. poj3691 DNA repair[DP+AC自动机]

    $给定 n 个模式串,和一个长度为 m 的原串 s,求至少修改原串中的几个字符可以使得原串中不包含任一个模式串.模式串总长度 ≤ 1000,m ≤ 1000.$ 先建出模式串的AC自动机,然后考虑怎么 ...