HashMap面试相关问题-为啥hashmap要使用红黑树,为啥不直接采用红黑树,而是当大于8个的时候才转换红黑树?何时会退化为链表?为何要二次哈希?.....

为啥hashmap不直接采用红黑树,而是当链表长度大于8个的时候才转换红黑树?小于6个转为链表?_小小梁的实验室的博客-CSDN博客_hashmap为什么不直接用红黑树

为啥hashmap不直接采用红黑树,而是当大于8个的时候才转换红黑树?_weixin_43968372的博客-CSDN博客_hashmap为什么不直接用红黑树

为啥hashmap要使用红黑树?
       
jdk1.7之前 只使用链表的话 如果链表太长会影响hashmap的性能

为什么不直接采用红黑树?
        时间:因为Map中桶的元素初始化是链表保存的,其查找性能是O(n),而树结构能将查找性能提升到O(log(n))。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。

        空间:因为红黑树需要进行左旋,右旋操作, 而单链表不需要,如果元素小于8个,查询成本高,新增成本低   如果元素大于8个,查询成本低,新增成本高    
           因为红黑树的平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,这才有转换为树的必要。链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。 还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低

为什么Map桶中个数超过8才转为红黑树?

        不过理想情况下随机hashCode算法下所有bin中节点的分布频率会遵循泊松分布,我们可以看到,在负载因子0.75的情况下,一个bin中链表长度达到8个元素的概率为0.00000006,几乎是不可能事件。所以,之所以选择8,是根据概率统计决定的,是为了让树化的几率足够小。

        红黑树的平均查找长度是log(n),如果长度为8,平均查找长度为log(8)=3,链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,这才有转换成树的必要;链表长度如果是小于等于6,6/2=3,而log(6)=2.6,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短.

何时会树化?
       
 当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时索引位置上的所有数据改为使用红黑树存储


何时会退化为链表?
          TreeNodes占用空间是普通Nodes的两倍,所以只有当bin包含足够多的节点时才会转成TreeNodes,当bin中节点数变少时,又会转成普通的bin。并且我们查看源码的时候发现,链表长度达到8就转成红黑树,在扩容时如果拆分树,当长度降到6就转成普通bin。remove树节点时 若root、root.right、root.left、root.left.left有一个为null 也会退化为链表 

索引如何计算?
         
 先计算对象的hashcode() 再进行调用HashMap的hash()方法进行二次哈希 最后&(caoacity-1)得到索引 比如capacity为16    那么%16和&(16-1)是等价的

为何要二次哈希而不是直接用hashcode计算索引?     
       
为了提高综合高位数据 让哈希分布更为均匀 避免出现链表过长的情况

eg:模拟足够随机的1000个元素放在大小固定为16的哈希表中

可以看到索引0放了63个元素.....每个索引放的元素数量都差不多 比较均匀

    模拟不够随机的1000个元素放在大小固定为16的哈希表中

 可以看到分布的很不均匀 如何解决呢?计算之前对hashcode值进行一次扰动(二次哈希)
        即:hash%capacity--->(hash^hash>>>16)%capacity

 
容量为何是2的n次幂? 
        计算索引时 若是2的n次幂 可以使用位与运算取代模运算 效率更高 扩容时 二次hash&oldCap==0的元素留在原来位置 否则新位置=旧位置+oldCap

数组容量不是2的n次幂行不行? 
       
可以.如果追求更高的效率采用2的n次幂作为容量 如果追求更好的哈希分散性选一个相对较为大的质数 选择质数都不用二次hash了   因为二次 hash 是为了配合 容量是 2 的 n 次幂 这一设计前提,如果 hash 表的容量不是 2 的 n 次幂,则不必二次 hash

加载因子为啥默认是0.75f?
            
加载因子是表示Hsah表中元素的填满的程度,HashMap中的加载因子 HashMap默认的加载因子是0.75,最大容量是16,因此可以得出HashMap的默认容量是:0.75*16=12
                1.在空间占用与查询时间之间取得较好的权衡
                2.大于这个值 空间节省了但是链表就会比较长 影响性能
                3.小于这个值 冲突减少了 但扩容就会更频繁 空间占用多

1.7/1.8put方法流程

多线程下会有啥问题?
   
    1.并发扩容死链(1.7)
        2.数据错乱(1.7 1.8)

key能否为null 作为key的对象有什么要求?
        hashmap的key可以为null 但map其他的实现不行
        作为key的对象 必须实现hashcode和equals 并且key的内容不可变

String对象的hashCode()如何设计 为啥每次乘31?

   ④质数产生hash冲突的概率较小。取的数太大的话又容易溢出。
                 
        

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值