HashMap是一个逻辑结构,其存储结构是一个链表数组。
单元格1 Enry1(k1,v1,next) --> Entry2(k2,v2,next) --> Entry
单元格2 Enry4(k4,v4,next)
单元格3 Enry1(k5,v5,next)
单元格4 Enry1(k6,v6,next)
单元格5 Enry1(k7,v7,next)
我决得这个结构可能从下面这些阶段过渡而来:(估计完全不是这么回事,方便自己理解就可以了)
1. 完全用一个链表实现
Enry1(k1,v1,next) --> Entry2(k2,v2,next) --> Entry(k3,v3,next) -->
put一个k,v时,直接放前面,其他的后移
get一个k时,遍历整个链表
2. 发展一下,发现链表遍历太慢了,分个组吧
group1:Entry1(k1,v1,next) --> Entry2(k2,v2,next) --> Entry(k3,v3,next) -->
group2:Entry4(k4,v4,next) --> Entry5(k5,v5,next) -->
put一个k,v,先将k进行一个运算,得到分组号,然后放到分组内的链表中,直接放前面,其他的后移
get一个k时,先将k进行一个运算,得到分组号,然后遍历分组内的链表,通过分组和k找到对应的节点。
3. 再发展一下,发现分组越散越好,分组号的计算是一个数学运算,非常快,分组散了,每个分组中的链表的长度就更短了,可能直接就是一个,也可能是多个,多个的话遍历也会很快。所以,这个将k运算成分组号的算法好好设计一下。
4. 定稿一下,给这个从k运算得出的分组号起个名字,叫hash值,一个hash值再运算,得出一个数组中一个索引号,可以直接找到数组的单元格。数组的单元格中是一个链表。
极致的分散近似形成一个一维数组,每个数组元素都是一个只有一个节点的链表,这样是速度最快的,这样的情况是追求的,需要一个好的hash算法。
不极致的情况,是存在多个k得到同一个hash值,找到同一个数组元素,将多个值串成一个链表,这样速度会慢一些,这些是不喜欢的,但也是准许和正确的,尽管我们管这种情况称为hash冲突。
put一个k,v,先将k的hashCode进行运算得到hash值,然后将hash值运算得到数组的索引号,找到一个单元格。先判断该单元格中是否包含该k对应的entry,包含则替换entry中的v。不包含则新建一个entry,封装k,v,next指向之前的entry链表中的第一个节点。
get一个k,先将k的hashCode进行运算得到hash值,然后将hash值运算得到数组的索引号,找到一个单元格,遍历单元格中的链表,找到hash,k都和当前k一样的节点,返回v。