极客时间学习日志,我理解散列表是数组的一种变种,散列表通过映射 将 key 映射为 数组下标。
散列表关联概念
关键字(key): 原始数据中的 标志信息,
散列函数(Hash函数):将 关键字 转化为 数组下标的 函数。常见:MD5 、SHA等
散列值: 散列函数的输出,一般为数组下标。
散列冲突: 不通的key值 ,通过散列函数,得到同样的散列值
装载因子: 装载因子 = 散列表中已经被占用的位置数量/散列表总长
散列函数设计原则
* 数组结果为 非负整数
* key1 != key2 ,hash(key1) != hash(key2)
* key1 = key2 , hash(key1) = hash(key2)
解决散列冲突的方法
-
开发寻址方法
- 线性探测法: 通过hansh 映射查看当前位置是否空闲,若被占用,则从头开始找,步长为1,直到找到空闲位置。
- 二次探测法: 通过hansh 映射查看当前位置是否空闲,若被占用,则从头开始找,步长变为上次的平方,直到找到空闲位置。
- 双重散列: 设置多个散列函数,hash1、hash2等,若hash1重复,用hash2 依次后推
-
链表法
散列表中的,每个数组下标对应的slot 变更为链表,讲hash 值相同的数据 均放入链表中。
散列表的时间复杂度
查找/删除/插入 最小时间复杂度为 O(1),最差为0(N)
应用
- 假设我们有 10 万条 URL 访问日志,如何按照访问次数给 URL 排序?
- 有两个字符串数组,每个数组大约有 10 万条字符串,如何快速找出两个数组中相同的字符串?
解决方案
- 遍历 10 万条数据,以 URL 为 key,访问次数为 value,存入散列表,同时记录下访问次数的最大值 K,时间复杂度 O(N)。
如果 K 不是很大,可以使用桶排序,时间复杂度 O(N)。如果 K 非常大(比如大于 10 万),就使用快速排序,复杂度 O(NlogN)。 - 以第一个字符串数组构建散列表,key 为字符串,value 为出现次数。再遍历第二个字符串数组,以字符串为 key 在散列表中查找,如果 value 大于零,说明存在相同字符串。时间复杂度 O(N)。