hashmap底层逻辑

  • 1.HashMap(1.8)底层数据结构是数组+链表+红黑树
  • 2.为什么要红黑树
    因为在极端情况,Hash冲突非常明显,所有的数据都存到链表中,时间复杂度就变成O(N),1.8之后采取链表长度>8转成红黑树,在hash冲突明显的情况下,查询时间复杂度O(logN)
  • 3.为什么HashMap数组长度需要是2的幂次方,如果输入不是2的幂次方会怎么样?
    在源码中使用 索引位置=hash & (数组长度-1) 代替 索引位置=hash % 数组长度,从而提升性能. 如果不是2的幂次方,在构造方法中有tableSizeFor会找到离传入长度最近的2的幂次方的值作为数组长度.
    假设源码中没有tableSizeFor方法会有什么问题? 比如长度为11,如果依然使用索引位置=hash & (数组长度-1) ,11个数组位置,1,3,5,7,9都获取不到的.
    面试题: HashMap map = new HashMap(10000); map.put()执行10001次,是否进行拓容了?
  • 4.put方法逻辑
    4.1 第一次执行put的时候,进行数组的初始化,默认容量为16,拓容阈值为 16 * 0.75 = 12. 0.75是负载因子,表示的数组的拥挤程度.
    4.2 获取传入key的hash值,然后进行高16位和低16的异或预算. 然后通过 hash & (n-1) 获取索引位置.
    4.3 判断索引位置的元素是否为空
    4.3.1 如果为空,直接创建Node对象,直接设置到数组的索引位置中.put方法结束了
    4.3.2 如果不为空,判断当前传入的key和索引位置的key是否相等(1.先比较hash值2.比较内存地址
    3.比较equals方法)
    链表
    4.3.2.1如果相等,覆盖旧值,返回旧值.
    4.3.2.1在链表中进行遍历,如果遍历完都没有,在链表尾部插入新的Node节点
    判断链表长度是否大于8,如果大于8
    情况1: 数组长度<64,进行拓容操作.
    情况2: 数组长度>=64,把链表转成红黑树(把单向链表变成双向链表,方便红黑树的遍历)
    4.4 数组长度+1,判断是否大于拓容阈值,就需要进行拓容的操作.
  • 5.拓容逻辑
    5.1 新数组长度=旧数组长度2 ,新的拓容阈值=旧的拓容阈值2
    5.2 拓容分这几种情况,进行遍历旧数组,把旧数组的内容复制新数组位置.
    5.2.1 旧数组索引位置上的元素为空,跳过
    5.2.2 旧数组索引位置上元素不为空,但是没有下一个节点. 说明只有一个元素,直接把这个元素放到新数组的对应位置 index = hash & (新数组长度-1)
    5.2.3 如果旧数组上是链表
    链表链表,判断元素放在新数组的哪个位置? 两种情况 1.存放在j位置【低位】 2.存放在j+旧数组长度位置.【高位】
    把单向链表分割成低位链表和高位链表
    newTab[j] = 低位链表的头结点 newTab[j+oldTabLen] = 高位链表的头结点
    5.2.3 如果旧数组上是红黑树
    把双向链表分割成低位双向链表和高位双向链表
    如果链表长度<6,把双向链表退化成单向链表
    newTab[j] = 低位双向链表的头结点 ,基于低位双向链表的头结点构建新的红黑树【当分裂成两个链表才需要】
    newTab[j+oldTabLen] = 高位双向链表的头结点 ,基于高位双向链表的头结点构建新的红黑树【当分裂成两个链表才需要】
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值