HashMap的实现原理

HashMap简介

  • 数据无序、底层由数组+链表+红黑树实现(JDK8开始)、容量是2的指数幂、初始大小为16(不指定长度)
  • 发生冲突时通过拉链法处理,当链表大于阈值时(阈值默认为8),将链表转化为红黑树
  • 时间复杂度:哈希查找O(1),哈希冲突多O(n),红黑树O(log n),平均O(1)

HashMap里面设计的算法(put和get操作原理)

  • 主要涉及哈希算法和寻址算法。哈希算法是在put过程中,根据传入key值获取对应hash值的一种方法;寻址算法在put和get过程中都有所运用,即根据hash值获得下标位置的方法。
哈希算法
  • 根据一个key,通过计算得到它对应的hash值(即将hash code向右移16位,再与原数值进行异或运算)(每个虚拟机对hash的计算都不一样,有些跟地址有关)
  • 直接使用hashcode做hash指的话,通过寻址算法所得结果有许多相同
  • 通过哈希算法的优化,一定程度避免了hash冲突,让数据更加散列
寻址算法
  • 根据hash值计算数组下标位置
  • 一个key的hash值,用这个hash值跟数组长度取模,就可以得到下标位置, 实际在源码中,采用了与运算代( 两个都是1,结果为1;不然是0 )替了取模(因为对于现代的处理器来说,除法和求余数(模运算)是最慢的动作)
  • 公式:(n - 1) & hash(n为数组长度)

put和get操作过程详解

put过程
  • 根据哈希算法获取哈希值
  • 哈希数组为空,则创建数组,默认初始大小为16
  • 对哈希值进行寻址运算,获取在数组中应该存入的下标位置,此时分为四种情况
  1. 如果该下标位置为空,则直接存入key,value键值对
  2. 如果不为空,只有一个元素且key相等,满足相等条件,替换旧值,不相等则拉链处理
  3. 如果该位置存了一个TreeNode,则说明是红黑树,执行树的插入操作
  4. 如果是一个链表,则遍历链表,如果中途有相等则替换,否则将key,value键值对插入链表最后;如果链表长度大于阈值 ,则转化为红黑树
get过程
  • 通过寻址算法找到key值应该对应的下标
  • 如果节点为空则返回空
  • 再判断首节点.key 是否和目标值相同, 相同则直接返回(首节点不用区分链表还是红黑树)
  • 首节点.next为空, 则直接返回空
  • 首节点是树形节点, 则进入红黑树数的取值流程, 并返回结果
  • 进入链表的取值流程, 并返回结果

HashMap的容量大小

如详解里面所提到的,HashMap的容量大小一般为2的指数次幂,在未指定初始大小的时候的默认大小为16,其原因有以下几点

  • 当n为2的指数幂时,根据寻址算法中的计算公式,n减1后换算成2进制,则每一位都为1,与hash进行与运算,就可 以得到(0~n-1)范围内的每一个index
  • 当n不为2的指数次幂时,减1后换算成2进制,会出现0,与hash进行与运算,会导致 (0~n-1)范围内的某些index永远得不到
  • 总结:当n不为2的指数幂时,有些地址永远得不到

加载因子和转化阈值

  • 加载因子又名负载因子、装载因子

  • 加载因子代表哈希表在其容量到达一定程度后,需要进行扩容

  • 负载因子越大表示散列表的装填程度越高,反之愈小

    负载因子越大, 对空间的利用更充分,但哈希碰撞机会变大,后果是查找效率的降低

    负载因子太小,对空间造成严重浪费,但数据稀疏使碰撞机会变小,查询效率提高

  • 加载因子0.75:根据泊松分布,加载因子为0.75时,节点出现在频率在Hash桶(表)中遵循参数平均为0.5的泊松分布。(源码没有解释,网上没统一答案)

  • 转化阈值8:用0.75作为加载因子时,桶中元素到达8个的时候,概率已经变得非常小,超过8个是几乎不可能的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值