引言
- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前面聊了一些底层的数据结构,然后我们来扩展一下,数组的存储和读写我们都熟悉了,我们所需要的数据是需要索引才能获取到,但是在实际的开发中,你所拥有的索引并不一定是数字,你得想办法转化成数字,那显然数组是不能满足要求的,于是我们引入了哈希表。
哈希表
假设我们有一个场景:就是用一个字符串key
取对应的商品信息也就是Value
,直接用数组取肯定是取不到的,于是我们就引入了哈希表,哈希表也是一种数据结构,底层其实是一个数组,但是此时我们的索引下标是通过Key
计算得到的,我们先通过key
拿到HasCode
,返回值是一个int
,然后再用HashCode
对数组取长度取余数,拿到余数就拿到对应商品的索引值了。拿到索引值对数据的读写就很方便了。
Hash冲突
这里有个疑问:如果使用哈希表在计算出的数组索引中已经有一个值了,那我们还要不要插入呢?如果插入就会覆盖原来的值,不插入这个值就会丢了,就让我们犯了难,怎么办呢?还记得前面提到的链表嘛?这个会很轻松的让我们解决这个问题,因为这个问题的本质就是数据插入问题,解决数据插入最直接的办法就是使用链表。
Hash表的改造
我们可以应用数组加链表的形式对Hash
表进行改造,数组不存储数据,key
或value
,数组只做Key
或Value
的指针,真正存储数据的是链表,这样我们解决了数据的存储问题,一旦发生Hash
冲突,只需要把相同下标不同Key
的元素存储起来就可以了,取的时候直接遍历链表找到对应的Key
就行了。
极端条件下,Hash
表会退变成链表,那我们查询数据的时间复杂度就又上来了,所以为了减少hash
冲突,我们也要分情况扩容,同时在HashCode
的计算中使0
和1
分布均匀,减少Hash
碰撞的产生。