1.定义
我们定义一个把字符串映射到整数的函数 \(f\),这个 \(f\) 称为是 Hash 函数。
我们希望这个函数 \(f\) 可以方便地帮我们判断两个字符串是否相等。
词汇“映射”
映射意为将一个集合中的任意元素和另一个集合中的元素一一对应。(请大佬指正)
2.思想
Hash 的核心思想在于,将输入映射到一个值域较小、可以方便比较的范围,也就是为了让两个字符串更加容易比较(感谢大佬yeyou26的指正)。
Warning
这里的「值域较小」在不同情况下意义不同。
3.性质
具体来说,哈希函数最重要的性质可以概括为下面两条:
\(1.\)在 Hash 函数值不一样的时候,两个字符串一定不一样;
\(2.\)在 Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)。
我们将 Hash 函数值一样但原字符串不一样的现象称为哈希碰撞。
引申:哈希碰撞
例子: $ K_{i} \neq K_{j} $
Hash( Ki) == Hash( Kj)
该种现象称为哈希冲突或哈希碰撞。
把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。
如何计算哈希
Warning:以下数学表达式较多,但有通俗易懂的解释,不要慌张。
计算哈希我们通常采用的是多项式 Hash 的方法,但是本蒟蒻并不会使用第一种,故使用第二种。
公式:
看公式,求和1~l s3*自定义变量b的i-1次方的值,所以xyz的哈希值为
我们假设b为3,则有
当i为1时,处理x,由于s[i]b的i-1次方,而i=1,故值为0;
当i为2时,处理y,由于由于s[i]b的i-1次方,而i=2,故值为1;
当i为3时,处理z,由于s[i]*b的i-1次方,而i=3,故值为2;
1+2=3,所以该字符串哈希值为3。
当然,最后结果还要Mod(模)M。
根据上方一次酣畅淋漓地推理,相信你已经看懂了过程,接下来讲述如何选择公式中的b与M
这里 M 需要选择一个素数(至少要比最大的字符要大),b 可以任意选择。因为如果M不为素数,为约数,哈希碰撞(上文提到过)的可能性会大大提升。
Hash 的准确率
懒得写了qwq(bushi)
管他干嘛?
实现
效率低下但容易理解的版本
int gethash(string s)
int res=0;
for(int i=0;i<s.size();i++)
res = ((long long)res * B + s[i]) % M;
return res;
这个程序最关键的一步就是res = ((ll)res * B + s[i]) % M;
套公式
当然我不是那种写显然的人,但剩下步骤真的很好理解!!!
以上就是无任何优化的哈希计算方法详解,感谢大佬观看。
接下来还会完善,不要着急.