散列
定义
- 将关键字映射到存储位置的过程称为散列。
- 散列是一种用以实现信息存储和快速检索的技术。
- 常用于执行优化搜索和符号表的实现。
效率
- 平均时间复杂度:O(1)
- 最坏时间复杂度:O(n)
散列的组成成分
- 散列表
- 散列函数
- 冲突
- 冲突解决技术
散列表
- 在数组中,关键字为k的元素将存储到数组的位置k。
- 给定关键字k,仅通过查看数组的第k个位置就可以找到该元素,这称为直接寻址。
- 当关键字的实际存储数目相对于关键字的取值范围较小时,可以使用散列表。
散列函数
散列函数用于将关键字转换成索引。
一个好的散列函数应具有一下特点:
- 最大限度减少冲突
- 简单并快速计算
- 将键值在散列表中均匀分布
- 能使用关键字提供的所有信息
- 对一组给定的关键字具有一个高负载因子
负载因子
负载因子 = 散列表中元素的个数 ÷ 散列表的长度
冲突
冲突是指两个记录通过散列函数映射到相同的地址空间。
冲突解决技术
寻找替代位置的过程称为冲突解决。
- 直接连接法:链表数组的应用
- 分离链接法
- 开放定址法:基于数组实现
- 线性探测法(线性搜索)
- 二次探测法(非线性搜索)
- 双重散列法(使用两个散列函数)
分离链接法
当两个或多个记录散列到相同的位置时,将这些记录构成一个单向链表
开放定址法
线性探测法
rehash(key) = (n + k) % tablesize (k为步长)
- 线性探测中,从发生冲突的原始位置开始按顺序搜索散列表,直到查找到未被占据的位置。
- 聚集是线性探测存在的一个问题,即散列表中包含一组连续的被占据的位置。
- 探测的下一个位置由步长确定,步长应该与散列表的长度互斥,较大的步长并不能避开聚集问题。
二次探测法
rehash(key) = (n + k²) % tablesize (k为1、2、3......)
- 二次探测中,从发生冲突的出事位置i开始,一次探测i+1²、i+2²、i+3²等。
- 尽管二次探测可以减少聚集,但还是存在聚集的可能
双重散列法
- 探测间隔由另一个散列函数计算生成,双重散列法更好地减少了聚集
- 第二个散列函数应遵循:h2(key) ≠ 0 且 h2 ≠ h1
- 双重散列中,依次探测h1(key)、 [h1(key)+h2(key)] mod tablesize、[h1(key)+2×h(key)] mod tablesize、[h1(key)+3×h(key)] mod tablesize、[h1(key)+4×h(key)] mod tablesize等。
- 使用少量探测序列,但需要花更多的时间
散列表实现及相关问题
https://github.com/liyizhu/structs-and-algorithm/tree/master/hash