通过一本英汉词典理解HashMap原理

Java中的HashMap是我们在编程时使用较多的一个类了,主要是它可以在常数时间实现插入,查询,删除操作。在JDK7中HashMap底层的数据组织结构就是一个数组+单链表。我们知道Map表示一组键值(key,value)对的映射,键之间不能重复,值无所谓。粗略说一下在HashMap中插入一个数据的过程:1、计算key的hash值。(就是一个对象与整数之间的映射)。2、计算储存索引。(hash值对底层数组长度取模)。3、判断在对应索引上是否已经有相同的key了,如果有,更改对应key的value值,否则插入key。

这么说可能有点抽象,第一次接触的同学肯定不知道在说些什么,下面让我们以一本字典来举个例子:

一本英汉词典就是一个再好不过的例子了,字典中英语单词对应的就是键(key),key之间不能重复(词典中肯定不会储存两个相同的单词),单词对应的汉语意思就是值(value),value之间是可以重复的,比如单词:go与leave都有离开的意思;good,fine,ok,well 都有好的意思:

如何实现常数时间的查找呢?

一般的词典都有有一个附录表,记录着单词和页码之间的对应:

 key和hash之间的映射是通过一个数学函数来计算得到,可以在O(1)时间内得到,在计算机里面没有储存着这样一个附录表,而是提供一个数学函数计算得到hash值的。(比如有些人把词典背的滚瓜烂熟,不需要查这个单词与页码之间的附录就知道一个单词在那一页了),有了hash值我们就可以知道储存对应key的索引了(对应到字典上的页码)。由于数组是支持随机访问的,那么我们在常数时间内访问到对应的索引,这也就实现了常数时间的访问了。

一般来说一部字典的一页可能会对应着好多单词,也就是说不同的key(单词)可能对应着同一个hash值(页码),在计算机里面,这叫作hash冲突,解决hash冲突常用的两种方法是:拉链法和开放地址探测法。在HashMap中就是使用拉链法来解决hash冲突的,底层使用一个单向链表来实现,类似于词典中的下图(为了画图方便,中间略过了一些单词):

这样如果我们想查找一个单词,就不用从好几万个单词中去找这个单词了,只需先计算要查找的单词的索引(计算hash值),然后去对应的页码查找,一下子从好几万解放到了十几个单词中,是不是大大提高了效率呢。当然一个hash函数要选用的合理,要使key的hash值均匀的分布在数组中,这样查找效率才高。举个极端的例子,如果所有的单词都被映射到了同一页上,那么我们想要查找一个单词就不得不遍历所有的单词才能找到我们想要的结果了,这样一个hash函数显然是不好的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值