接前面
匹配——散列法里面只说前一个字符乘以128再对72057594037927931求模,答案乘以128加后一个字符再对72057594037927931求模。对应代码:
hash_s = (DOMAIN * hash_s + ord(s[i])) % PRIME
用例
还是用书上这个例子
>>>rabin_karp_matching('aabcbabcaabcaababc','abcaababc')
9
>>>
公式
h
a
s
h
(
l
e
n
t
)
=
(
s
[
0
]
∗
D
O
M
A
I
N
L
−
1
+
s
[
1
]
∗
D
O
M
A
I
N
L
−
2
+
s
[
2
]
∗
D
O
M
A
I
N
L
−
3
+
.
.
.
+
s
[
L
−
2
]
∗
D
O
M
A
I
N
1
+
s
[
L
−
1
]
∗
D
O
M
A
I
N
0
)
m
o
d
P
R
I
M
E
hash(len_t) = (s[0]*DOMAIN^{L-1} + s[1]*DOMAIN^{L-2} + s[2]*DOMAIN^{L-3} + ...+ s[L-2]*DOMAIN^1 + s[L-1]*DOMAIN^0 ) mod PRIME
hash(lent)=(s[0]∗DOMAINL−1+s[1]∗DOMAINL−2+s[2]∗DOMAINL−3+...+s[L−2]∗DOMAIN1+s[L−1]∗DOMAIN0)modPRIME
从hash_s打印的结果看,第一次是97,第二次12513,第三次1601762到7,8位的时候就是个17位的数了,跟公式应该对得上的。
滚动
代码只有三行,是怎么就去掉了第一个值out_digit的影响,再右移添加in_digit,完成一个循环的计算?
val = (old_val - out_digit * last_pos + DOMAIN*PRIME) % PRIME
val = (val * DOMAIN) % PRIME
return (val + in_digit) % PRIME
参数里last_pos是干什么的?old_val是前一次的散列值。
last_pos
last_pos = pow(DOMAIN, len_t -1) % PRIME #计算中没有变的。他写成算式是 D O M A I N L − 1 DOMAIN^{L-1} DOMAINL−1, 前面公式里第一个s[0]乘以的值,即 s [ 0 ] ∗ D O M A I N L − 1 s[0]*DOMAIN^{L-1} s[0]∗DOMAINL−1.只有一行一行看代码了。
第三行
return (val + in_digit) % PRIME
跟接前面那一行很像,但他是DOMAIN * hash_s加上新值再对PRIME求模。val可以变成这样的行式吗?
第二行
val = (val * DOMAIN) % PRIME
他多求了一次模,为什么要多求模?没事,不明白就先注释掉,两行变一行写成
return (val * DOMAIN + in_digit) % PRIME
打印的结果也是9,那第一行就是去掉第一个值out_digit的影响吗?
第一行
val = (old_val - out_digit * last_pos + DOMAIN*PRIME) % PRIME
按前面的公式来说减掉out_digit * last_pos,即 s [ 0 ] ∗ D O M A I N L − 1 s[0]*DOMAIN^{L-1} s[0]∗DOMAINL−1.这里为什么多了个DOMAIN*PRIME。不明白的就去掉。
def roll_hash(old_val, out_digit, in_digit, last_pos):
#val = (old_val - out_digit * last_pos + DOMAIN*PRIME) % PRIME#去掉out的值
val = (old_val - out_digit * last_pos) % PRIME#去掉out的值
#val = (val * DOMAIN) % PRIME
#return (val + in_digit) % PRIME
return (val * DOMAIN + in_digit) % PRIME
这样打印的也是9,都有点不敢相信,字符前面加66也打印11了。
>>> rabin_karp_matching('aabcbabcaabcaababc','abcaababc')
9
>>> rabin_karp_matching('66aabcbabcaabcaababc','abcaababc')
11
>>>
证明
看了很多网上的证明,也没怎么明白,只能理解到前面的第一个公式。求模不影响四则运算吗,
求模怎么影响四则运算的?把17位的质数改成101,DOMAIN也改成2,证明还是打印的11
PRIME=101#72057594037927931 #17位
DOMAIN=2#128
后话
求模