哈希表
- 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
- 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
- 以上选自百度百科-散列表
哈希函数 address = H(key)
理想的哈希函数是指能将key尽可能均匀的散布
到整个定长数组中。均匀的散布
也就意味着极少的哈希冲突
构造方法 | 说明 | 适用场景 |
---|---|---|
直接寻址法 | 通过线性函数 H(key) = a*key + b 计算地址 | 适用于需要散列的key之间也是线性关系的情况 |
除留余数法 | 通过 H(key) = key % P (P <= 数组长度, 多数会取素数 ) 计算地址 | 最简单,最常用的方法 |
随机数法 | 通过 H(key) = random(key) 将key 作为随机数种子 | 适用于key长度不等时。 |
平方取中法 | 通过 key 的平方 然后取中间特定几位的方式 计算出散列地址 详情-Jeff_ | 无法确定关键字中哪几位分布较均匀的时候 |
折叠法 | 通过 将 key 分成长度相等的几部分,然后叠加舍去进位 | 适用于关键字位数比较多,且关键字中每一位上数字分布大致均匀时 |
数字分析法 | 出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址 | 适用于哈希表中可能出现的关键字都是事先知道的并且数字之间满足进制关系 |
- 散列: 将key通过哈希函数计算成地址的过程
哈希冲突和处理办法
哈希冲突
在使用哈希函数计算地址的时候,不可避免的会出现 key 不同但哈希后的地址一样的情况,这种情况就叫哈希冲突
处理办法
开放地址法
对于发成冲突的计算结果,将key加入特定的值后再进行哈希计算得到新的值,如新值未冲突就写,否则继续加入特定值计算哈希
链地址法
将发生冲突的key对应位置由存储为value进化为存储有一个个value的链表 此时对于此位置的查询由 O(1) 退化为 O(n) n为链表长度
公共溢出区
在声明哈希表的存储空间的时候,额外开辟一份空间用来存储冲突的地址
再哈希法
提前准备多个哈希函数,如果第一个冲突了,就用第二个依次类推
- 在实际编程语言中,大多会采用
链地址法
处理哈希冲突,并且在链表过长的情况下将链表转为红黑树加速查询 - 合理的哈希算法可以有效减少哈希冲突,比如Java通过位运算加快函数速度,额外的扰动函数提取更多key的特征来优化
除留余数法
- 合理的装载因子,装载因子 当前使用的位置/总可用位置 的值,如果值过大就会加大产生哈希冲突的概率
算法应用
- 简单 快乐数
- 布隆过滤器(Bloom Filter) 通过散列的形式快速判断 一个值是否在一个拥有海量值的集合中。
参考
- java哈希表的细节实现 https://zhuanlan.zhihu.com/p/123261109
这写的比我好多了
https://mp.weixin.qq.com/s/P0NUr86J3OCZFsn-aJAbtg