HashMap 原理及常见面试题

之前有面试问道hashMap 的问题,感觉又熟悉又陌生,今天重新查看源码把问题记录下(本文基于jdk1.8进行分析)

 

1、问题一:hashMap的底层实现?

 

 

 

 首先HashMap内部有一个叫做Node的静态内部类,每个Node 存有hash值,key,value,和指向下一个Node的指针(链表结构)

 

 

 整体上可以猜测每一个node会维护一个链表来存储

然后再看HashMap&put 方法

 

 所以基本上hashMap的一个结构如下:

 

 

数组下表是由 hash & lengh - 1   决定的

所以hashMap是由 数组+链表+红黑树实现的

 

2、问题二:HashMap hash冲突是怎么解决的?

这个问题之前hashmap没有引入红黑树的时候, hash & lengh - 1 算出的index相同使用的是链表的单链表的形式,相同的散列值由头指向尾查找最后能添加的位置进行插入,

这样导致的问题是每次冲突了算法复杂度o(n),jdk1.8中将大于8的单链表转化成红黑树进行存储,使得插入和查找最大复杂度为 o(logn)

 

3、问题三:红黑树的插入算法?

满足5个条件的树叫做红黑树

a、任何一个节点要么是红要么是黑

b、根节点是黑

c、叶子节点是黑(叶结点即指树尾端NIL指针或NULL结点)

d、如果一个结点是红的,那么它的两个儿子都是黑的。 

e、对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。

插入的算法如下:

i、将插入的节点置为红

ii、插入的父节点为空树,直接将插入节点置黑

iii、插入的父节点为黑,直接插入节点

iiii、插入的父节点为红,叔节点为红色,将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点

iiii、插入的父节点为红,叔叔节点为黑,当前节点是其父节点的右子节点,当前节点的父节点做为新的当前节点,以新当前节点为支点左旋

iiiii、插入的父节点为红,叔叔节点为黑,当前节点是其父节点的左子节点,父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋

 

上面是红黑树插入的算法,

hashmap里面红黑树具体代码是从根节点往后查找,插入的hash值小于节点,取left子节点,反之取right子节点直到叶子节点进行插入

 

 

红黑树插入实现代码

 

 4、问题4:hashmap的扩容算法是怎样的?

 

 

 

 5、问题5 hashmap 为什么使用红黑树优化hash冲突而不是用查找树?

 

查找树是一种任何左子树比父亲节点小,右子树比父亲节点大的树,查找时可以使用二分法来进行查找,最好的情况是

 

 

 事件复杂度 o(logn),但是查找树如果只有左子树,或者只有右子树的情况就会退化成为一个链表

 

 

 这种情况下的查找复杂度在  o(logn)~o(n)之间,而红黑树的效率是o(logn),所以使用红黑树更好

6、为什么不适用平衡树来代替红黑树呢?

平衡树是从查找树变化来的 每个节点的左子树和右子树的高度差至多等于1,这个条件过于苛刻,基本每次插入都需要通过左旋或者右旋进行调整树的结构效率太低,虽然平衡树的查找效率是o(logn)

7、HashMap中hash函数怎么实现的?

  

 

   hashcode的高16位不变,低16位变成(高十六位^低十六位),这个得到的hash&(length-1) 便得到了数组下标

  

这么做是为了提高取模效率

 

具体效果参考网站: http://rbtree.phpisfuture.com/

 

posted on 2022-02-20 22:28  老公公-Q  阅读(284)  评论(0编辑  收藏  举报

导航