一、哈希表
1.基本介绍
哈希表(Hash table,国内也有一些算法书籍翻译为散列表)是根据关键码的值而直接进行访问的数据结构。每个是以键值对key-value形式存储
其实数组就是一张哈希表。哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素
2.作用
一般哈希表都是用来快速判断一个元素是否出现集合里
eg:要查询一个名字是否在这所学校里。
要枚举的话时间复杂度是
O
(
n
)
O(n)
O(n),但如果使用哈希表的话, 只需要
O
(
1
)
O(1)
O(1)就可以做到。
我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。
将学生姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。
3.哈希函数
哈希函数,把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。
哈希函数能快速将一个数值转换成哈希值(整数)。所以哈希表必须保持哈希值的计算一致,如果两个哈希值是不相同的,那么这两个哈希值的原始输入也是不相同的。
通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了
如果hashCode得到的数值大于tableSize了,此时为了保证映射出来的索引数值都落在哈希表上,会在再次对数值做一个取模的操作,就要我们就保证了学生姓名一定可以映射到哈希表上了。
4.哈希碰撞
两元素映射到了同一索引位置,这一现象叫做哈希碰撞或哈希冲突。
一般哈希碰撞有两种解决方法, 拉链法和线性探测法。
拉链法
将发生冲突的元素都存储在索引位置的链表中
拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。
线性探测法
使用线性探测法,一定要保证tableSize(哈希表的大小)大于dataSize(数据规模)。 我们需要依靠哈希表中的空位来解决碰撞问题。例如冲突的位置,放了A,那么就向下找一个空位放置B的信息。
5.常见的三种哈希结构
使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构:
- 数组
- set (集合)
- map(映射)
使用数组来做哈希的题目,是因为题目限制了数值的大小。若没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果元素个数少,哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
但使用set占用空间比数组大,而且速度要比数组慢,set把数值映射到key上要做hash计算
set是一个集合,里面放的元素只能是一个key。Map是映射结构,存放key-value键值对。
6.应用
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
如果在做题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!