算法笔记4.2 散列(哈希)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法笔记4.2 散列(哈希)相关的知识,希望对你有一定的参考价值。
- 这是《算法笔记》的读书记录
- 本文参考自4.2节
文章目录
- 1. 散列
- (1)定义
- (2)关键问题
- 2. 整数的散列
- 3. 其他数据类型的散列
- 4. 编程中的应用
1. 散列
(1)定义
- 散列(hash)是一个常用思想,很多程序中都有意无意地会用到。 一句话说,散列就是 “将一个元素通过一个函数转换为整数,使得这个整数可以尽量唯一地代表这个元素”,这个转换函数称为 “散列函数 H”
- 经过散列函数处理,我们就可以把元素本身作为一个key/索引/下标…,进而实现时间复杂度为O(1)的查询。所以散列本质上是用通过空间换时间,实现快速查询的一种算法
(2)关键问题
- 散列函数H的设计:如何把原始数据集的每个元素映射到尽量互不相同的整数
- 直接定址法:
H(key) = a*key+b
- 数字分析法:适用于key是多位整数的情况,取key的若干数位组成哈希地址
- 平方取中法:关键字平方后取中间几位
- 折叠法:把关键字分割成位数相同的几段,取这几段的叠加和
- …
- 冲突的解决方法:当两个元素数据映射到同一个整数时,如何解决冲突
- 线性探查法:若
H(key)
位置已被占据,就检查H(key)+1
是否为空,如果也被占据就继续检查H(key)+2
,这样不断向后探查直到找到一个空位置,如果后移到数组尾部,则返回到数组首部继续。这种方法保证只要哈希表未满,总能找到一个不冲突的地址,但是容易产生聚集影响效率 - 二次探测再散列:线性探查法是向一个方向找, 二次探测再散列是来回找,移动序列为,这样不保证能找到不冲突地址,但不易发生聚集
- 伪随机探测再散列:和上两种类似,只是移动序列为随机序列
- 再哈希法:设定多个不同的散列函数,第一个函数计算发生冲突,就换第二个再算,直到不冲突为止
- 链地址法:这种方法不需要重新计算哈希值,而是把所有哈希值相同的key链接为一个单链表
- 如何查找
- 一般的方法是:仿照建表过程,先用key计算H(key)作为下标,访问哈希表元素比较key,若不等,说明建表时发生了冲突,用建表时使用的冲突解决方法依次向后找,直到key比较相等为止
2. 整数的散列
- 整数本身就是散列的目标输出,因此散列函数可以简单地表示为
H(key)=key
(直接定址法) - 举例来说,我们现在给出两个整数集合A和B,分别有M和N个元素,要判断B中的每个数是否在A中出现过
- 常规思路:二重遍历,时间复杂度
O(M*N)
- 使用散列:开一个大数组,在输入A时,用A中整数元素作为数组下标,对数组做标记。判断时只要用B中整数元素作为数组下标查询数组即可,时间复杂度
O(M+N)
- PAT乙级中 “翻转链表” 这个题的正解就运用了整数散列的思路,否则一定会超时:反转链表 (25)
3. 其他数据类型的散列
- 上面第一部分的散列方法基本都是针对于整数key而言的,要应用到其他数据类型,可以先简单地把数据转换为整数,再用上述方法,或者转换为整数后直接作为key。要注意的是,散列函数和冲突解决方法的设计都会影响效率
- 举例来说,要设计一个英文单词的哈希函数,可以把大写字母转换为
0~25
,小写字母转换为26~51
,这就相当于把一个英文单词转换为52进制数,直接转10进制就可以作为key了
4. 编程中的应用
- 做编程题时往往不会自己写散列函数和冲突处理什么的,而是采用STL提供的工具。
map
和unordered_map
(C++11)都可以用于散列
以上是关于算法笔记4.2 散列(哈希)的主要内容,如果未能解决你的问题,请参考以下文章