前言
今天去面试啊,聊得差不多的时候面试官突然问我会手写 HashMap 吗?这我哪能怂啊,好死不死的面试之前我还真手写过一个简单的 HashMap,所以我不过花了 5 分钟便弄出来了,面试官直呼内行。
相信大家关于 HashMap 的面试题刷的也不少了,源码应该也看了很多遍,大部分人可以说是非常熟悉了,但是如果面试官突然给你们整这么一手,我相信很多人还是会表示懵逼的。所以今天给大伙捋一捋,掌握手写 HashMap 之后都给我去手撕面试官。
除了 hashmap 之外我还整理了很多经典面试题,做成了一本 PDF,内容不多,但全是干货,需要的朋友可以点击这里领取>>互联网公司Java面试核心知识
HashMap 是 Java 中一中非常常用的数据结构,也基本是面试中的“必考题”。它实现了基于“K-V”形式的键值对的高效存取。JDK1.7 之前,HashMap 是基于数组+链表实现的,1.8 以后,HashMap 的底层实现中加入了红黑树用于提升查找效率。
HashMap 根据存入的键值对中的 key 计算对应的 index,也就是它在数组中的存储位置。当发生哈希冲突时,即不同的 key 计算出了相同的 index,HashMap 就会在对应位置生成链表。当链表的长度超过 8 时,链表就会转化为红黑树。
手写 HashMap 之前,我们讨论一个小问题:当我们在 HashMap 中根据 key 查找 value 时,在数组、链表、红黑树三种情况下,平均要做多少次比较?
在数组中查找时,我们可以通过 key 的 hashcode 直接计算它在数组中的位置,比较次数为 1
在链表中查找时,根据 next 引用依次比较各个节点的 key,长度为 n 的链表节点平均比较次数为 n/2
在红黑树中查找时,由于红黑树的特性,节点数为 n 的红黑树平均比较次数为 log(n)
前面我们提到,链表长度超过 8 时树化(TREEIFY),正是因为 n=8,就是 log(n) < n/2 的阈值。而 n<6 时,log(n) > n/2,红黑树解除树化(UNTREEIFY)。另外我们可以看到,想要提高 HashMap 的效率,最重要的就是尽量避免生成链表,或者说尽量减少链表的长度,避免哈希冲突,降低 key 的比较次数。
手写 HashMap
定义一个 Map 接口
也可以使用 Java 中的java.util.Map
public interface MyMap<K,V> {
V put(K k, V v);
V get(K k);
int size();
V remove(K k);
boolean i