hashmap小结

问题:

1.hashmap底层实现原理?数据结构?

2.size为什么是2的n次幂?

3.put实现?

4.hashmap为了解决hash冲突做了哪些事情?

5.扩容机制?

6.扩容之后,新旧table数组数据怎么迁移?迁移过程中做了哪些操作保证了node的均匀分布?

 

解答:

   计算key的hashcode(hash值计算采用的是高16位和hah与或^操作,为了让高16位也参与hash算法,目的是为了让node分布均匀,减少hash冲突的概率),

    1.计算key在table =node[]中的下标:(用key的hash%size-1,源码中采用的巧妙的算法,用&代替%,因为%操作相对于&操作效率较低:前提是table.size必须是2的n次幂

    

     计算出key的下标位置后,有两种情况:

如果没有发生碰撞,直接添加元素到散列表中去

如果发生了碰撞(hashCode值相同),进行三种判断

    1:若key地址相同或者equals后内容相同,则替换旧值

    2:如果是红黑树结构,就调用树的插入方法

    3:链表结构,循环遍历直到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的阀值8;也可以遍历到有节点与插入元素的哈希值和内容相同,进行覆盖。

如果桶满了大于阀值,则resize进行扩容

 

为什么HashMap的默认负载因子是0.75,而不是0.5或者是整数1呢?
答案有两种:

阈值(threshold) = 负载因子(loadFactor) x 容量(capacity) 根据HashMap的扩容机制,他会保证容量(capacity)的值永远都是2的幂 为了保证负载因子x容量的结果是一个整数,这个值是0.75(4/3)比较合理,因为这个数和任何2的次幂乘积结果都是整数。

理论上来讲,负载因子越大,导致哈希冲突的概率也就越大,负载因子越小,费的空间也就越大,这是一个无法避免的利弊关系,所以通过一个简单的数学推理,可以测算出这个数值在0.75左右是比较合理的

 

扩容:

调用场景:

1.初始化数组table

2.当数组table的size达到阙值时即++size > load factor * capacity 时,也是在putVal函数中

实现过程:

1.通过判断旧数组的容量是否大于0来判断数组是否初始化过

否:进行初始化

  • 判断是否调用无参构造器,

    • 是:使用默认的大小和阙值

    • 否:使用构造函数中初始化的容量,当然这个容量是经过tableSizefor计算后的2的次幂数

是,进行扩容,扩容成两倍(小于最大值的情况下),之后在进行将元素重新进行与运算复制到新的散列表(这里的key的hash需要重新计算hash,具体也是用hash&(newTable.length-1)这样保证了在原来oldTable中相同下标的Node链表,在迁移到新的newTable时,原来的低位链还是在原来的下标(i),而高位链则是在(i+newTable.length)位置上,这样Node相对分布均匀,减少了hash冲突的概率

概括的讲:扩容需要重新分配一个新数组,新数组是老数组的2倍长,然后遍历整个老结构,把所有的元素挨个重新hash分配到新结构中去。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值