HashMap面试题

数组初始化:

1.在第一次放入数据时,会先初始化数组,默认长度16

但是如果是2,4或者8会不会有点小,添加不了多少数据就会扩容,也就是会频繁扩容,这样岂不是影响性能,那为啥不是32或者更大,那不就浪费空间了嘛,所以啊,16就作为一个非常合适的经验值保留了下来。

2. 如果指定了参数初始化HashMap,会通过下面方法算出一个长度进行扩容,保证都是2的  整数次方。               

 

扩容:

条件:大于容量*负载因子

3.当数组的如果没有超过1<<30最大长度,则进行扩容,长度为原来的两倍

 

扩容的时候为什么1.8 不用重新hash就可以直接定位原节点在新数据的位置呢?

 

 

put操作

1.如果数组为空,则进行初始化数组

2.如果数组不空,根据key算出hash值,然后取得数组的下标,查看该位置是否有值,如果没有则new一个node节点

3.如果有值,比较key是否相同,如果相同进行值覆盖

4.如果不相同,判断头结点是否是红黑树,如果是进行插入到红黑树

5.如果是链表,遍历链表,比较key是否相同,如果相同则值覆盖

6.如果遍历到链尾,数据插入到链尾,同时判断链表的长度>=8,如果是则进行链表转换成红黑树,

如果数组的长度<64,则进行扩容,否则建立红黑树

7.判断是否需要扩容( 元素数量>数组大小(默认16)* loadFactor(默认0.75)

 

 

为什么负载因子loadFactor是0.75?

0.75是时间跟空间上达到一个平衡的一个值。

 

为什么红黑树是转换条件是8?

1.在理想情况下,链表长度符合泊松分布,各个长度的命中概率依次递减,当长度为 8 的时候,概率仅为 0.00000006。这是一个小于千万分之一的概率,概率已经很低了。选择了8作为阀值(官网解释)

 

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

 

 

               

什么时候红黑树会退化成链表?

桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表。主要是一个过渡,避免链表和红黑树之间频繁的转换。如果阈值是7的话,删除一个元素红黑树就必须退化为链表,增加一个元素就必须树化,来回不断的转换结构无疑会降低性能,所以阈值才不设置的那么临界。

   

 

HashMap 为什么选择红黑树


因为AVL树插入节点或者删除节点,整体的性能是不如红黑树的。AVL每个左右节点的高度是不能大于1的。所以维持这种结构比较消耗性能。主要还是左旋右旋改变与维护AVL高度问题,红黑树比他好的就是只需改变节点颜色就可以了。

二分查找树,他的左右节点不平衡,一开始就固定了root,那么极端的情况下会成为链表结构。

链表长度越长,那么他的插入和查询效率都很低。

而红黑树他的整体查找,增删节点的效率都是比较高的。
 

为什么扰动函数?

 

1.使用扰动函数就是为了增加随机性,让数据元素更加均衡的散列,减少碰撞。

2.算法一定要尽可能高效,因为这是高频操作, 因此采用位运算;

 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

 

1.8还有三点主要的优化:

1.数组+链表改成了数组+链表或红黑树;将时间复杂度由O(n)降为O(logn);


2.链表的插入方式从头插法改成了尾插法,简单说就是插入时,如果数组位置上已经有元素,1.7将新元素放到数组中,原始节点作为新节点的后继节点,1.8遍历链表,将元素放置到链表的最后;避免了在多线程环境下会1.7版本扩容会产生环


3.扩容的时候1.7需要对原数组中的元素进行重新hash定位在新数组的位置,1.8采用更简单的判断逻辑,位置不变或索引+旧容量大小;


4.在插入时,1.7先判断是否需要扩容,再插入,1.8先进行插入,插入完成再判断是否需要扩容;

1.8在put值的时候,如果是覆盖原理的值,会直接返回,不需要扩容,如果先判断是否要扩容后插入的话比较浪费时间

 

面试题:

https://angela.blog.youkuaiyun.com/article/details/104889549?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

 

参考:

https://bugstack.blog.youkuaiyun.com/article/details/107903915

https://www.cnblogs.com/myseries/p/10876828.html

https://www.cnblogs.com/jzb-blog/p/6637823.html

https://www.cnblogs.com/yanzige/p/8392142.html

https://blog.youkuaiyun.com/LovePluto/article/details/79755496?utm_term=hashmap%E5%85%88%E6%8F%92%E5%85%A5%E5%86%8D%E6%89%A9%E5%AE%B9&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-0-79755496&spm=3001.4430

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值