Hash哈希与哈希表
Hash哈希与哈希表
字符串哈希
概念
哈希算法是通过一个哈希函数H(C),将一种数据(字符串,较大的数等)转化为能够用变量或下标表示的数,这样转化得到的值叫做哈希值。通过哈希值可以实现快速查找与匹配。
例题描述
【Substring Matching】给出两个串\(S1,S2\)(仅有大写字母),求\(S1\)在\(S2\)中出现几次。
[input:]
ABC
ABCABCABBBABCABBCABC
[output:]
4
如果我们用\(O(m)\)的时间复杂度计算字符串的哈希值,复杂度依然是\(O(nm)\)——没有任何改变。
所以我们采用滚动哈希的优化技巧。我们选择两个互质的常数\(b\)和\(k\)\((b < k)\),假设字符串为\(C = c_1c_2 \cdots c_m\) ,我们用\(b\)进制数的方式计算哈希值可以得到:\(H(C) = (c_1b^{m - 1} + c_2b^{m - 2} + \cdots + c_mb^{0}) \ mod \ h\)
我们可以将这个过程用前缀和思想计算,设\(H(C,k)\)为前\(k\)个字符构成的字符串的哈希值,则:(一下取模均用自动溢出的方式进行)
则主串中\([k + 1,k + m]\)区间内的字符构成的字符串哈希值可以表示为:
总的时间复杂度就变成了\(O(n + m)\)
哈希表
概念
哈希表是一种高效的数据结构,查询插入的时间复杂度也近似于常数。哈希表的实现本质上就是用空间换取时间,在可用内存较大时,哈希表非常划算。
算法实现
为了使查询时间缩短,我们让查询的值作为下标\(Book[key] = key\)。但这样存储显然非常浪费空间,尤其是对于稀疏的数据。为了使空间开销减少,我们设计一个哈希函数\(H(key)\),并令\(Book[H[key]] = key\)。
但这样又会存在新的问题,假设\(H(key) = key \ mod \ 13\) 。那么我们就会发现\(H(1) = H(40) = 1\),后面出现的\(40\)将前面的\(1\)覆盖了。我们不妨将数组内每一个元素看作一个集合\(A_i = \{x|H(x) = i\}\),这样时间复杂度就取决于集合的大小。
哈希函数的构造
显然哈希函数是决定查找效率的关键,我们设计的哈希函数应尽量使哈希值均匀分布,这样每个集合的大小越小,时间复杂度越低。
-
除余法
哈希函数是这样的形式:
\[H(key) = key \ mod \ b \]在实际问题中\(b\)应取小于且接近数组空间大小的质数。
-
乘积取整法
哈希函数是这样的形式:
\[H(key) = \lfloor M \times (key \times A \ mod \ 1) \rfloor \]\(A\)是一个在\((0,1)\)区间的实数(尽量使用无理数,\(\cfrac{\sqrt{5}-1}{2}\)是一个很好的数)
\(M\)是哈希表的大小
-
基数转化法
基数转化法就是将\(key\)改变为另外一种进制的数,再用除余法取余(两基数互质)。
\[H(key) = (k_1b^{m - 1} + k_2b^{m - 2} + \cdots + k_mb^{0}) \ mod \ h \]\(k_i\)为\(key\)各个位上的数,\(b\)为基数

浙公网安备 33010602011771号