高产真是高产
看的出来吧, 我一直在学习 !
1概述
哈希表(散列表)是一种数据结构, 它可以通过哈希函数将关键码映射到表中的某个位置, 从而使查找复杂度为O(1)
Address = Hash(key)
哈希函数通常是一个压缩映射函数, 必定存在多对一的情况, 也就是说一定会存在冲突
对于哈希函数的选择我们需要考虑两点: 分布均匀、尽量减少冲突;如何解决冲突。
实际编程中我们很少用到原理部分, 我们通常使用C++11中的unordered_set、unordered_map
2 哈希函数
2.1 除留余数法
很简单的一种,就是运用了模运算 hash(key) = key % p
关于p的选择:p选择不大于m(哈希表长度)接近m的质数, 若p选择2的i次幂, 则地址就是key的后i位二进制数字, 如key = 7(111), p = 2^2 = 4, add = 3(11)
2.2 数学分析法
分析所有出现的关键码, 选取某些分布均匀的位作为地址
2.3 平方取中法
将key平方后(扩大差别)再选取key^2的某几位(取决于m)
2.4 折叠法
将key按照哈希表地址空间位数划分成相等的几组叠加起来, 叠加方法有移位法和分界法
```eg: 239 385 878 41
239 239
385 583
878 878
41 14
1543 1714(去掉最高位)
```
3 处理闭散列的方法
3.1 线性探测法(linear probing)
冲突的话, 就从冲突的地方向后移找地址, 容易聚集
Hi = (Hi-1 + 1) % m
3.2 二次探测法(quadratic probing)
Hi = (H0 - i^2) % m Hi = (H0 + i^2) % m;
解决了单方向堆积, 减轻了堆积
但是可能有空间也找不到,因为 H0, H0 + 1, H0 - 1, H0 + 4, H0 - 4
所以散列表的大小必须是4k + 3的质数, 避免有些地方探测不到
3.3 双散列法
就是用两个散列函数, 一个平常计算用,另一个冲突了再用
3.4 再散列法
如果冲突了是元素太多了,我们重新扩充散列表,重新散列(好累)
4 处理开散列的方法
就是每个桶内放的是一个链表, 冲突了就往后接就行了
5 总结
哈希表适合用于查找较多、关键字比较计算量比较大, 空间换时间, 与问题的规模n无关, 不适合顺序查找关键字