0x14 Hash

0x14 Hash

1.Hash

Hash表又称为散列表,一般由Hash函数(散列函数)与链表结构共同实现。与离散化思想类似,当我们要对若干复杂信息进行统计时,可以使用Hash函数把这些复杂信息映射到容易维护的值域上来。因为值域变简单、范围变小,有可能造成两个不同的原始信息被Hash函数映射为相同的值,所以我们需要处理这种出现冲突的情况。

有一种称为“开散列”的解决方案是,建立一个领接表结构,以Hash函数的值域作为表头数组head,映射后值相同的原始信息被分到同一类,构成一个链表接在对应的表头之后,链表的节点上可以保存一些原始信息和统计数据。

Hash表主要包括两个基础操作:

1.计算Hash函数的值。

2.定位到对应链表中依次遍历、比较。

当Hash函数设计较好时,原始信息会比较均匀的分布在各个表头之后,从而使每次查找、统计的时间降到“原始信息总数除以表头数组长度”。若原始信息总数和表头数组长度都是 O ( n ) O(n) O(n)级别且Hash函数分散均匀,几乎不产生冲突,则每次查找、统计的时间复杂度期望都是 O ( 1 ) O(1) O(1)

2.字符串Hash

下面介绍的字符串Hash函数把一个任意长度的字符串映射成一个非负整数,并且其冲突概率几乎为零。

取一固定值P,把字符串看作P进制数,并分配一个大于0的数值,代表每种字符。一般来说,我们分配的数值都远小于P。例如,对于小写字母构成的字符串,可以令a=1,b=2,c=3,...,z=26取一个固定值M,求出该P进制数对M的余数,作为该字符串的Hash值

一般来说,我们取P=131或P=13331,此时Hash值产生冲突的概率极低,只要Hash值相同,我们就可以认为原字符串是相等的。通常我们取 M = 2 64 M=2^{64} M=264,即直接使用unsigned long long类型存储这个Hash值,在计算时不处理算术溢出问题,产生溢出时相当于直接对 2 64 2^{64} 264取模,这样可以避免低效的取模(mod)运算,同时也可以避免负数出现问题

除了在极特殊构造的数据上,上述Hash函数很难出现冲突,一般情况下上述Hash函数完全可以出现在题目的标准解答中。我们还可以多取一些恰当的P和M的值(例如大质数),多进行几组Hash运算,当结果都相等时可以认为原字符串相等,就更难以构造出产生Hash冲突的值。

对于字符串的各种操作,我们都可以反映到P进制数的运算上。

已知字符串S的Hash值为 H ( S ) H(S) H(S),那么新字符串S+c的Hash值就是 H ( S + c ) = ( H ( S ) ∗ p + v a l u e [ c ] ) m o d M H(S+c)=(H(S)*p+value[c])modM H(S+c)=(H(S)p+value[c])modM。其中乘P相当于P进制下的左移运算, v a l u e [ c ] value[c] value[c]是我们为c选定的代表数值。

如果字符串S的Hash值为 H ( S ) H(S) H(S),字符串S+T的Hash值便为 H ( S + T ) H(S+T) H(S+T),那么字符串T的Hash值便为 H ( T ) = H ( S + T ) − H ( S ) ∗ p l e n g t h ( T )   m o d   M H(T)=H(S+T)-H(S)*p^{length(T)}\bmod M H(T)=H(S+T)H(S)plength(T)modM

例如,S="abc"​c="d"​,则:

S表示为P进制数 :1 2 3

H ( S ) = 1 ∗ p 2 + 2 ∗ p + 3 H(S)=1*p^2+2*p+3 H(S)=1p2+2p+3

H ( S + c ) = 1 ∗ p 3 + 2 ∗ p 2 + 3 ∗ p + 4 = H ( S ) ∗ p + 4 H(S+c)=1*p^3+2*p^2+3*p+4=H(S)*p+4 H(S+c)=1p3+2p2+3p+4=H(S)p+4

根据上面两种操作我们可以在 O ( N ) O(N) O(N)的时间里预处理字符串所有前缀Hash值,并在 O ( 1 ) O(1) O(1)的时间里查询它的任意子串的Hash值

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷神星ceres

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值