HashMap的实现原理及红黑树

在JDK1.7及之前hashMap采用 数组+链表 形式 链表的插入采用的是头插法
在JDK1.8的时候,hashMap采用 数组+链表(红黑树) 链表改成了尾插法,并且引入了红黑树。

  • HashMap的实现原理
    其实就是有个Entry 数组,Entry保存了key和value。当你要塞入一个键值对的时候,会根据一个hash算法计算key 的hash值,然后通过数组大小n-1 & hash值之后,得到一个数组的下标,然后往那个位置塞入这个Entry。
    然后我们知道,hash算法是可能产生冲突的,且数组的大小是有限的,所以很可能通过不同的key计算得到一样的下标,因此为了解决Entry冲突的问题,采用了链表法,如下图所示:
    HashMap的实现原理及红黑树_第1张图片
    在JDK1.7及之前链表的插入采用的是头插法,即在链表的头部插入新的Entry
    在JDK1.8的时候,改成了尾插法,并且引入了红黑树。
    HashMap的实现原理及红黑树_第2张图片

    当链表的长度大于8且数组大小大于等于64的时候,就把链表转化成红黑树
    当红黑树节点小于6的时候,又会退化成链表。

  • 为什么JDK 1.8要对HashMap做红黑树这个改动?
    主要是避免hash冲突导致链表的长度过长,这样get的时候时间复杂度严格来说就不是O(1)了,因为可能需要遍历链表来查找命中的Entry。

  • 为什么定义链表长度为8且数组大小大于等于64才转红黑树?不要链表直接用红黑树不就得了吗?
    在这里插入图片描述
    因为红黑树节点的大小是普通节点大小的两倍,所以为了节省内存空间不会直接只用红黑树,只有当节点到达一定数量才会转成红黑树,这里定义的是8。
    为什么是8呢?这个其实HashMap注释上也有说的,和泊松分布有关系,这个大学应该都
    学过。
    HashMap的实现原理及红黑树_第3张图片
    简单翻译下就是在默认阈值是0.75的情况下,冲突节点长度为8的概率为0.00000006,也就概率比较小(毕竟红黑树耗内存,且链表长度短点时遍历的还是很快的)。
    这就是基于时间和空间的平衡了,红黑树占用内存大,所以节点少就不用红黑树,如果万一
    真的冲突很多,就用红黑树,选个参数为8的大小,就是为了平衡时间空间的问题。

  • 为什么节点少于6要从红黑树转成链表?
    也是为了平衡时间和空间,节点太链表遍历也很快,没必要成红黑树,变成链表节约内存。

  • 为什么定了6而不是小于等于8就变?
    是因为要留个缓冲余地,避免反复横跳。举个例子,一个节点反复添加,从8变成9,链表变红黑树,又删了,从9变成8,又从红黑树变链表,再添加,又从链表变红黑树?
    所以余一点,毕竟树化和反树化都是有开销的。

红黑树:一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红。或黑

HashMap的实现原理及红黑树_第4张图片

  • 红黑树特点:
  1. 每个节点或者是黑色,或者是红色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子点!]
  4. 如果一个节点是红色的,则它的子节点必须是黑色的。
  5. 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
  • 基本操作:左旋,右旋,添加,删除
    HashMap的实现原理及红黑树_第5张图片

你可能感兴趣的:(java,mysql,spring)