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\)个字符构成的字符串的哈希值,则:(一下取模均用自动溢出的方式进行)

\[H(C,k + 1) = H(C,k) + c_{k} b^{k - 1} \]

则主串中\([k + 1,k + m]\)区间内的字符构成的字符串哈希值可以表示为:

\[H(C') = \frac{H(C,k + m) - H(C,k))}{b^k} \]

总的时间复杂度就变成了\(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\}\),这样时间复杂度就取决于集合的大小。

哈希函数的构造

显然哈希函数是决定查找效率的关键,我们设计的哈希函数应尽量使哈希值均匀分布,这样每个集合的大小越小,时间复杂度越低。

  1. 除余法

    哈希函数是这样的形式:

    \[H(key) = key \ mod \ b \]

    在实际问题中\(b\)应取小于且接近数组空间大小的质数。

  2. 乘积取整法

    哈希函数是这样的形式:

    \[H(key) = \lfloor M \times (key \times A \ mod \ 1) \rfloor \]

    \(A\)是一个在\((0,1)\)区间的实数(尽量使用无理数,\(\cfrac{\sqrt{5}-1}{2}\)是一个很好的数)

    \(M\)是哈希表的大小

  3. 基数转化法

    基数转化法就是将\(key\)改变为另外一种进制的数,再用除余法取余(两基数互质)。

    \[H(key) = (k_1b^{m - 1} + k_2b^{m - 2} + \cdots + k_mb^{0}) \ mod \ h \]

    \(k_i\)\(key\)各个位上的数,\(b\)为基数

posted @ 2025-03-09 23:17  nightmare_lhh  阅读(47)  评论(0)    收藏  举报