Hash表的理论基础:
哈希表(Hash Table):
什么是哈希表?哈希表(Hash table——正确的翻译是散列表,国内选择音译)。
哈希表是根据 关键码 的值而直接进行访问的数据结构。
这样理解可能会有点困难,我们来举个例子,数组就是一张哈希表。
数组中关键码是什么呢——就是索引下标。我们可以通过==关键码(索引)==直接访问元素。
哈希表能解决什么问题呢?
一般,哈希表是用来快速判断一个元素是否出现在集合里。
我们只需要计算出元素的关键码,那我们就可以直接判断该元素是否在哈希表上。
那么如何计算元素的关键码呢?这就需要使用哈希函数(hash function)了。
哈希函数(Hash Function):
哈希函数,会通过hashCode()把元素转化为数值,一般 hashCode()是通过特定编码方式,可以将其它数据格式转化为不同的数值,这样就可以确定在哈希表上的索引位置了。
若我们通过 hashCode 得到的数值 > 哈希表的大小(tableSize)了,怎么办呢?
为了确保映射出来的索引数值都落在哈希表上,我们会对hashCode得到的数值进行一个取模操作,这样就能保证索引可以映射到哈希表上了。
但是我们在添加元素的时候,很有可能我们想要添加的元素个数 > 我们一开始创建的数组的总大小,就算我们使用 %数组的容量,也会导致有几个元素映射到了哈希表的同一个索引位置。
这就是哈希碰撞。
哈希碰撞:
即有多个元素映射到了同一个索引位置处,这就叫做哈希碰撞。
拉链法:
将数组中存放的元素变成链表,那么我们如果有多个元素映射到了同一个索引位置处,那我们就可以将新的元素添加到原来元素的后面了。(java 中的 HashMap 和 HashSet 都是如此实现的,当然他们懂得实现更加复杂,还有红黑树)。
常见的数据结构:
放我们想使用哈希法来解决问题的时候,一般选择下面三种数据结构:
- 数组;
- Set(集合);
- Map(映射)。
总结:
当我们遇到了要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法。
但是哈希发是牺牲了空间换取时间。
若我们在面试或者算法题中遇到需要判断一个元素是否出现过的常见,那我们应该想到哈希法。