背景 在1.7之前的版本,当数组元素较多(几百.几千,或者更多)的时候,在这种前提扩容,涉及全量元素的遍历和坐标的重新定位,这个耗时会比较长.这是之前存在的一个弊端吧.那么引入红黑树之后就解决了问题,那是怎么解决的呢,我说下自己的理解. 过程分析 既然数组扩容导致了变慢,那就是从扩容方向思考,谁决定了扩容呢?负载因子和数组长度.数组长度是resize自动做的,所以对用户来讲这应该是一个关注不到的变量,那就只剩负载因子了.负载因子越大,扩容的频率就越低. 1. 负载因子较小(小于1) hash碰撞…
JDK1.8中的HashMap实现跟JDK1.7中的实现有很大差别.下面分析JDK1.8中的实现,主要看put和get方法. 构造方法的时候并没有初始化,而是在第一次put的时候初始化 putVal方法的主要逻辑是这样的: 1.如果数组还没有初始化(数组长度是0),则先初始化 2.通过hash方法计算key的hash值,进而计算得到应该放置到数组的位置 3.如果该位置为空,则直接放置此处 4.如果该位置不为空,而且元素是红黑树,则插入到其中 5.如果是链表,则遍历链表,如果找到相等的元素则替换,…
一.JDK1.7中HashMap扩容死锁问题 我们首先来看一下JDK1.7中put方法的源码 我们打开addEntry方法如下,它会判断数组当前容量是否已经超过的阈值,例如假设当前的数组容量是16,加载因子为0.75,即超过了12,并且刚好要插入的索引处有元素,这时候就需要进行扩容操作,可以看到resize扩容大小是原数组的两倍,仍然符合数组的长度是2的指数次幂 我们再进入resize方法如下,它首先会对之前的数组容量进行判断,看是否已经达到了数组最大容量,如果没有,后面会进行数组的转移操作,即…
怎样才能让HashMap以红黑树类型存储数据? 看上面的代码可知:如果一个Node的长度大于等于7.就会触发Node转TreeNode的操作. 我向一个map中插入了一百万条数据(插入一亿条时,内存溢出了),也没有发现代码走这一步.是我的数据量不够大,还是操作有问题? 求大佬解答…
(这篇文章暂时鸽了,有点理解不能,点进来的小伙伴可以撤了) 刚开始准备在HashMap中直接把红黑树也过了的,结果发现这个类不是一般的麻烦,所以单独开一篇. 由于红黑树之前完全没接触过,所以这篇博客相当于探索(其实之前的博客都是边看源码边写的,全是探索). 红黑树没见过,树我还是知道的,所以先上一张帅图: 红黑树在这个基本树的基础上还多了red,暂时不知道啥意思,慢慢探索. 先来一个类总览: static final class TreeNode<K,V> extends LinkedHash…
为什么HashMap使用红黑树而不使用AVL树? 红黑树适用于大量插入和删除:因为它是非严格的平衡树:只要从根节点到叶子节点的最长路径不超过最短路径的2倍,就不用进行平衡调节 AVL 树是严格的平衡树,上述的最短路径与最长路径的差不能超过 1,AVL 允许的差值小:在进行大量插入和删除操作时,会频繁地进行平衡调整,严重降低效率: 红黑树虽然不是严格的平衡树,但是其依旧是平衡树:查找效率是 O(logn): AVL也是 O(logn): 红黑树舍去了严格的平衡,使其插入,删除,查找的效率稳定在 O…
JDK 1.8 HashMap是数组+链表+红黑树实现的,在阅读HashMap的源码之前先来回顾一下大学课本数据结构中的哈希表和红黑树. 什么是哈希表? 在存储结构中,关键值key通过一种关系f和唯一的存储位置相对应,关系f即哈希函数,Hash(k)=f(k).按这个思想建立的表就是哈希表. 当有两个不相等的关键字key1和key2,但f(key1)=f(key2)这两个key地址相同,就发生了冲突现象. 冲突不能避免只能减少,通过设计均匀的哈希函数来减少. 常用哈希函数? 1. 直接定址法 H…
一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. (方块表示Entry对象,横排表示数组table[],纵排表示哈希桶bucket[实际上是一个由Entry组成的链表,新加入的Entry放在链头,最先加入的放在链尾],) 二.实现原理 成员变量 源码分析: /** 初始容量,默认16 */ static final int DEFAULT_INITIAL_CAPACITY = 1 <<…
前言: hashmap是一种很常用的数据结构,其使用方便快捷,接下来笔者将给大家深入解析这个数据结构,让大家能在用的时候知其然,也知其所以然. 一.Map 首先,从最基本的讲起,我们先来认识一下map是个什么东西.在我们写程序的时候经常会遇到数据检索等操作,对于几百个数据的小程序而言,数据的存储方式或是检索策略没有太大影响,但对于大数据,效率就会差很远.我们来讨论一下这个问题. 1.线性检索: 线性检索是最为直白的方法,把所有数据都遍历一遍,然后找到你所需要的数据.其对应的数据结构就是数组,链表…
红黑树的设计,相比 jdk1.7 的 HashMap 而言,jdk1.8 最重要的就是引入了红黑树的设计,当冲突的链表长度超过 8 个的时候,链表结构就会转为红黑树结构. 01.故事的起因 “ JDK1.8 最重要的就是引入了红黑树的设计(当冲突的链表长度超过 8 个的时候),为什么要这样设计呢?好处就是避免在最极端的情况下冲突链表变得很长很长,在查询的时候,效率会非常慢. 红黑树查询:其访问性能近似于折半查找,时间复杂度 O(logn): 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度…