本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目:请实现一个最简单HashMap
我们经常使用HashMap, 经过各个版本的迭代,源代码看起来也是十分的头大
这次我们通过自己实现HashMap来看看,究竟会有哪些东西!
二、代码演示
问题描述
一组 7 个的字符串,需要存放到数组中,要求在获取每个元素的时候时间复杂度是 O(1)。也就是说你不能通过循环遍历的方式进行获取,而是要定位到数组下标直接获取相应的元素。
解决方案
如果说我们需要通过 ID 从数组中获取元素,那么就需要把每个字符串都计算出一个在数组中的位置 ID。字符串获取 ID 你能想到什么方式? 一个字符串最直接的获取跟数字相关的信息就是 HashCode,可 HashCode 的取值范围太大 了[-2147483648, 2147483647],不可能直接使用。那么就需要使用 HashCode 与数组长度做与运算,得到一个可以在数组中出现的位置。如果说有两个元素得到同样的 ID,那么这个数组 ID 下就存放两个字符串。
代码实现
public static void main(String[] args) {
// 初始化一组字符串
List<String> list = new ArrayList<>();
list.add("钢铁侠");
list.add("浩克");
list.add("雷神");
list.add("美国队长");
list.add("惊奇队长");
list.add("蜘蛛侠");
list.add("黑豹");
// 定义要存放的数组
String[] tab = new String[8];
// 循环存放
for (String key : list) {
int idx = key.hashCode() & (tab.length - 1); // 计算索引位置
System.out.println(String.format("key 值=%s Idx=%d", key, idx));
if (null == tab[idx]) {
tab[idx] = key;
continue;
}
tab[idx] = tab[idx] + "->" + key;
}
}
- 初始化一组字符串集合,这里初始化了 7 个。
- 定义一个数组用于存放字符串,注意这里的长度是 8,也就是 2 的倍数。这样的数组长度才会出现一个 0111 除高位以外都是 1 的特征,也是为了散列。
- 接下来就是循环存放数据,计算出每个字符串在数组中的位置。key.hashCode() & (tab.length - 1)。
- 在字符串存放到数组的过程,如果遇到相同的元素,进行连接操作模拟链表的过程。
- 最后输出存放结果
测试结果
key 值=钢铁侠 Idx=1
key 值=浩克 Idx=2
key 值=雷神 Idx=7
key 值=美国队长 Idx=7
key 值=惊奇队长 Idx=5
key 值=蜘蛛侠 Idx=5
key 值=黑豹 Idx=0
["黑豹","钢铁侠","浩克",null,null,"惊奇队长->蜘蛛侠",null,"雷神->美国队长"]
三、思考分析
在测试结果首先是计算出每个元素在数组的 Idx,也有出现重复的位置
最后是测试结果的输出,3、4、6,位置是空的 5、7,位置有两个元素被链接起来 惊奇队长->蜘蛛侠 & 雷神->美国队长
这就达到了我们一个最基本的要求,将串元素散列存放到数组中,最后通过字符串元素的索引 ID 进行获取对应字符串。这样是 HashMap 的一个最基本原理,有了这个基础后面就会更容易理解 HashMap 的源码实现。
四、总结
本篇主要是作为开头,了解HashMap的实现原理,接下来会讲到HashMap的散列表与扰动函数 感冒了头疼,HashMap的文章会接着更新,本文主要参考程序员小傅哥的Java面经PDF