什么是hashMap--抄自小灰

1、hashmap是一个用于存储key-value键值对的集合,每一个键值对也叫做Entry。这些键值对分散存储在一个数组当中,这个数组就是hashmap的主干。

hashmap数组每一个元素的初始值都是Null。
在这里插入图片描述
对于hashmap,最常使用的两个方法:get 和 put

2、put方法的原理
调用put方法的时候发生了什么呢?比如调用hashMap.put(“apple”,0),插入一个key为apple的元素,而上面有说到数组是hashmap的主干,那么也就是说需要知道新插入的元素所在的数组的下标。此时可以利用一个哈希函数来确定entry的插入位置(index)。
如:index = hash(“apple”)
假如最后计算出的index是2,那么结果如下:
在这里插入图片描述
但是,由于hashmap的长度是有限的,如果仅使用上面的hash算法,当插入的entry越来越多时,还是会出现index冲突。
如下所示:
在这里插入图片描述
这时候该怎么办呢?可以利用链表来解决。
hashmap数组的每一个元素不止是一个entry对象,也是一个链表的头节点,每一个entry对象通过next指针指向它的下一个entry节点,当新来的entry映射到冲突的数组位置时,只需要插入到对应的链表即可:
在这里插入图片描述
那意思就是实际插入的就是一个链表?(这里的entry是一个键值对,其实就是hashmap中的单个元素)

3、get方法的原理
使用get方法根据key来查找value。首先会把输入的key做一次hash映射,得到对应的index:
在这里插入图片描述
由于刚才所说的hash冲突,同一个位置有可能匹配到多个entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。假设我们要查找的key是apple:
在这里插入图片描述
第一步:查看的是头节点entry6,entry6的key是banana,显然不是我们要找的结果。
第二步:我们查看的是next节点entry1,entry1的key是apple,正是我们要找的结果
之所以把entry6放在头节点,是因为hashmap的发明者认为:后插入的entry被查找的可能性更大。

(也就是时候,hashmap本质上是一个数组,数组中的每一个元素就是一个键值对,在put的时候,是通过算法+key计算出应该保存在哪个下标里,而由于算法计算出来的结果可能存在重复,所以如果是同一个下标的时候,就通过链表的方式保存。而在get的时候,同样是通过key+算法计算出下标,然后通过下标从数组中获取到数据,而获取到的数据可能是一个链表,那么此时就通过key来一个个进行对比,最终获取到key所对应的value值。)

3、hashmap的初始长度
hashmap的初始长度是16,并且每次自动扩展或者手动初始化时,长度必须是2的幂。
(之所以要选择16,就是为了服务于从key映射到inex的hash算法)
之前说过,从key映射到hashmap数组的对应位置,会用到一个hash函数:
index = hash(“apple”)
那如何实现一个尽量均匀分布的hash函数呢?可以通过利用key的hashcode值来做某种运算。
为了实现高效的hash算法,hashmap的发明者采用了位运算的方式:其中length是hashmap的长度。
在这里插入图片描述
下面我们以值为book的key来演算整个过程:
1、计算book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001
2、假定hashmap长度是默认的16,计算length-1的结果为十进制的15,二进制的1111.
3、把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,十进制9,所以index=9

可以说,hash算法最终得到的index结果,完全取决于key的hashcode值的最后几位。
那长度为什么必须是16或者2的幂呢?因为这样做不但效果上等同于取模,而且还大大提高了性能,至于为什么采用16,可以试试长度为10会出现什么问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图所示,选用了三个hashcode,但是计算的结果都是1001,也就是说,当hashmap长度为10的时候,有些index结果出现机率会更大,而有些index则永远不会出现。所以这样是不符合hash算法均匀分布的原则。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章