由红黑树引出的HashMap扩容机制的思考

红黑树是什么?

由红黑树引出的HashMap扩容机制的思考_第1张图片

三大特点:

  1. 根节点是黑色,叶节点是不存储数据的黑色空节点

  2. 任何相邻的两个节点不能同时为红色

  3. 任意节点到其可到达的节点间包含相同数量的黑色节点

联想:Java HashMap底层红黑树原理

HashMap基于哈希表Map接口实现,是以key-value存储形式存在,即主要用于存储键值对。

HashMap特点:

  1. 存取无序

  2. 键和值位置都可以为null,但是键的位置为null只能有一个

  3. 键位置是唯一的,底层数据结构控制键

哈希冲突:

定义:两个对象调用的hashCode方法计算的哈希码值一致导致计算机的数组索引值相同

HashMap底层数据结构

JDK1.8之前,HashMap是由数组+链表组成的,数组是HashMap主体,链表用来解决哈希冲突。即,发生hash冲突后使用equals判断是否相等,相等则存储在该节点的链表中。

JDK1.8之后,当链表长度大于阈值(或者红黑树的边界值,默认为8),并且当前数组长度大于64时,此时索引位置上的所有数据改为红黑树存储。

创建对象底层原理:

HashMap map = new HashMap<>();
  1. 当创建HashMap集合对象时,

    • 在JDK8前,构造方法中创建一个长度是16的Entry[] table 用来存储键值对数据的

    • 在JDK8后,不是在HashMap的构造方法底层创建数组了,而是在第一次使用put方法时,创建的数组,Node[] table用来存储键值对数据的

  2. 存储数据数组位置为空时:

    • 比如将一个键值对 (“Benaso” ,1) 存储到哈希表中,根据 “Benaso” 调用 String 类中重写之后的hashCode() 方法计算出值,然后结合数组的长度采用某种算法算出向Node数组中存储数据的空间值索引,如果该索引对应空间没有数据,则将 (“Benaso” ,1) 存储到数组中

    • 面试题:哈希表底层采用何种算法计算hash值?还有哪些算法可以计算出hash值?

      • 底层采用key的hashCode方法的值结合数组长度进行无符号右移(>>>)、按位异或(^),按位与(&)计算出索引。(异或:两个二进制值相同为0,不同为1)

      • 还可以采用平方取中法,取余数,伪随机数法

      • 哈希表采用方法原因是与其他方法相比该方法效率高

  3. 存储数据数组位置不为空时:

    • 例如向hash表新存一组数据(“Victor” ,1),假设根据Victor计算出的hashCode方法结合数组长度计算出的索引值也是3,那么此时数组空间不是null,此时则会比较Victor的hash值是否一致,如果不一致,则在此空间上划出一个节点来存储键值对数据 (“Victor” ,1)。——这种方法被称为拉链法

  4. 假设向哈希表中存储数据 (“Benaso” ,2) 那么根据Benaso调用hashCode方法结合数组长度计算出索引也为3,此时对比较后存储的数据Benaso和已经存在的Benaso的hash值是否相等,如果相等,发生hash碰撞:

    • 相等:则将后添加的数据的value覆盖到其上

    • 不相等:那么继续向下和其它数据的key进行比较,如果都不相等,则划出一个节点存储数据。

  5. 一般不会等到存储数据到达16才扩容,

    threshold(临界值)= capacity(容量) * loadFactor(加载因子)

    这个值是当前已占用数组长度的最大值,size超过这个临界值就重新resize(扩容),扩容后的 HashMap 容量是之前容量的两倍。

HashMap集合类的成员

成员变量

集合的初始化容量(必须是二的n次幂

//默认初始容量是16 -- 1<<4相当于1*2的4次方 --- 1*16
static final int DEFAULT_INITAL_CAPACITY = 1 << 4

HashMap扩容

扩容条件

  1. 元素个数超过12扩容,

  2. 链表节点大于8,数组长度小于64

扩容后索引要么是原索引,要么是原索引加16

  • 计算新的索引高位是0那么存储到原来索引位置

  • 如果高位是1那么存储到原来索引加旧的数组的长度

你可能感兴趣的:(Java学习思考,java,数据结构,hash)