我正在尝试使用Horner的规则将单词转换为整数。我理解它是如何工作的,如果这个词很长,它可能会导致溢出。我的最终目标是在散列函数h(x)= x mod tableSize中使用转换后的整数。我的书建议,由于溢出,你可以“在计算Horner规则中的每个带括号的表达式之后应用mod运算符。”我并不完全明白这是什么意思。说表达式如下:
((14 * 32 + 15)* 32 + 20)* 32 + 5
我是否在每个带括号的表达式后使用mod tableSize并将它们一起添加?这个哈希函数和霍纳规则的例子会是什么样子?
答案 0 :(得分:5)
这本书说你应该利用这些数学等价:
(a * b) mod m = ((a mod m) * (b mod m)) mod m
(a + b) mod m = ((a mod m) + (b mod m)) mod m
因此,
h = (((x*c) + y)*c + z) mod m
相当于
_ _ _ _
h = (((x*c) + y)*c + z)
其中
_
a * b = ((a mod m) * (b mod m)) mod m
_
a + b = ((a mod m) + (b mod m)) mod m
基本上,对于每个基本加法和基本减法,您将其替换为mod
操作数和mod
结果的“高级”版本。由于基本乘法的操作数现在在0..m-1
范围内,因此您获得的最大数字是(m-1)^2
,如果m
足够小,可以减轻溢出。
-1 mod 2 = 1
以数学方式,但Java中的-1 % 2
为-1
。顺便说一下,应该指出32对于这个类的哈希函数来说是一个可怕的乘数选择(因为它不是素数),特别是对于计算(因为它是2的幂)。更好的是31,因为:
31 * i == (i << 5) - i
答案 1 :(得分:2)
它们意味着用结果mod tableSize:
替换带括号的表达式的结果((((14*32+15)%tableSize)*32+20)%tableSize)*32+5
答案 2 :(得分:1)
使用Java代码更容易理解这一点。我们应该在循环内的计算中的每一步应用模运算符:
public static int hashCode(String key) {
int hashVal = 0;
for (int j = 0; j < key.length(); j++) {
// For small letters.
int letter = key.charAt(j) - 96;
hashVal = (hashVal * 32 + letter) % arraySize; // mod
}
return hashVal;
}