[知识点] 7.2 哈希表

Posted jinkun113

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[知识点] 7.2 哈希表相关的知识,希望对你有一定的参考价值。

前言

很久很久以前经常听到哈希这个词,后来多多少少有所接触,但并未系统地了解过哈希到底是怎么回事。

子目录列表

1、哈希表与数组

哈希表(hash table),又称为散列表,是根据关键码值(key)直接进行访问的一种数据结构,也就是说,给定一个 key,则可以通过哈希表的映射关系快速找到其对应的值(value)。这听起来似乎和数组是一个意思 —— 对于数组 a = {2, 5, 8},其元素 a[1] = 2, a[2] = 5, a[3] = 8,没错,数组本身就是一种 key-value 的对应关系,每个元素的编号为 key,值为 value —— 而哈希表在数组的基础上有什么改进?

2、哈希函数

给定一个哈希表,存在函数 f(key),对任意给定的 key 值,通过代入这个函数就能得到包含该 key 的记录在表中的地址,则这个函数叫做哈希函数。哈希的目的是让本来复杂的数据以简单的方式体现或访问,举个例子:给定 10 个同年同月同日同地出生的人的身份证号码,并为这些号码编一个号以便以后使用,比如:

a[320115********0105] = 1
a[320115********8577] = 2
...
a[320115********5201] = 10

显然,开一个 18 位数大小的数组是不现实的,我们决定将这些数进行哈希——由于这些号码前 14 位都是相同的,我们将这 18 位的 key 值取后 4 位来替换原 key 值进行各类操作,一下就变得现实起来了:

a[105] = 1
a[8577] = 2
...
a[5201] = 10

而后我们需要输出或其他情况时,把前 14 位还原即可。

所以,在生活中,我们常说的手机尾号便是手机号的哈希值,假设尾号为 4 位,其哈希函数为 f(key) = key % 10 ^ 4;小明在学校的学号为 1810141728,而在班上提交作业时使用的学号为 28,本质是完整学号的哈希值,哈希函数为 f(key) = key % 100。

而对于普通的数组,可以理解成哈希函数为 f(key) = key。

那么,如何构造一个哈希函数?有什么要求?

 

3、哈希冲突

上面举的几个例子中,10 个身份证号码的后 4 位理论上是不会有重复的;小明在班上交作业,班上也不会有和他一样尾号为 28 的;但对于手机尾号,假设张三的手机号为 155****1666,李四的手机号为 189****1666,那么他们在讨论手机号时,肯定不会用后 4 位尾号,因为并不能分清到底是谁的手机号,对于这种两个不同的原值通过哈希函数得到的哈希值相同的情况,我们称之为哈希冲突。

对于所有情况,哈希函数如何定义并无规定,但显然,我们要保证不出现哈希冲突的情况,或者尽可能少到忽略不计,即保证其哈希结果的正确性。而正确性与空间占用往往是成反比的,其正确性越高,哈希值范围越大, 所占用的空间也就越大,所以我们需要在其中找到平衡点,下面介绍几种常见的构造哈希函数的方法。

 

4、构造哈希函数

① 直接寻址法

取 key 或 key 的某个线性函数值作为哈希值,即 f(key) = a * key + b。

构造方便,但适用范围不广。

举例:

小明统计这次高数考试成绩,每 10 分为一个分段。分数为 key,分数段人数为 value,则哈希函数可以设定为 f(key) = 0.1 * key,通过哈希使 key 范围缩小至 1 / 10。

② 数学分析法

通过对 key 值的分析,找到最不可能出现冲突的构造方式,上述的手机尾号、学号等直接 key 值取模便是属于这种。

③ 平方取中法

求出 key 值的平方,取该平方值的中间几位作为哈希值。听起来也是个比较玄学的构造方法,当然取最中间的数也是不无道理的 —— 它们和 key 的每一位都会相关,出现冲突的概率较低。由于存在平方操作,key 值不能过大。

举例:

key = 77777,key ^ 2 = 6049261729,f(key) 可以取 9261。?

④ 折叠法

将 key 值按照数位平均切割为若干部分,求出每一部分各个数位之和,最后将这些和首尾相连,得到 f(key)。

举例:

key = 123456789,可以拆分成 123, 456, 789,分别求和为 6, 15, 24,再合并成 61524,即 f(key)。

⑤ 随机数法

选择一个随机函数,取随机值作为哈希值,即 f(key) = random(key)。

随机大法好。

⑥ 除留余数法

取 key 被某个

5、字符串 hash

上述所有哈希方法都是整数与整数之间的映射,但哈希的适用范围绝不局限于此。

以上是关于[知识点] 7.2 哈希表的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript笔试题(js高级代码片段)

HashMap原理:哈希函数的设计

Redis哈希表总结

[知识点] 5.2 字符串hash

[知识点] 5.2 字符串hash

Python算法教程第二章知识点:计时模块字典与散哈希表图与树的实现成员查询插入对象