我被赋予这个算法来编写一个哈希函数:
BEGIN哈希(字符串)
UNSIGNED INTEGER键= 0;
FOR_EACH字符IN字符串
key =((key<<< 5)+ key)^ character;
结束FOR_EACH
返回键;
结束哈希
<<
运算符指向左侧的移位位。 ^
指的是XOR操作,字符指的是字符的ASCII值。看起来非常简单。
以下是我的代码
unsigned int key = 0;
for (int i = 0; i < data.length(); i++) {
key = ((key<<5) + key) ^ (int)data[i];
}
return key;
然而,当我真的应该从0 - n
得到一个哈希值时,我会继续得到荒谬的正面和负面的巨大数字。 n
是用户预先设置的值。我不确定哪里出了问题,但我认为这可能是XOR
操作。
任何建议或意见将不胜感激。谢谢!
答案 0 :(得分:5)
此代码的输出是32位(或64位或宽{/ 1}}无符号整数)。要将其限制在0到 n -1的范围内,只需使用unsigned int
运算符将其模数 n :
%
(显而易见的是,您的代码,如写的,无法返回&#34;哈希值从0 - unsigned int hash = key % n;
&#34;,因为n
不会出现在代码中的任何位置。)
事实上,有一个很好的理由不过早地减少模数 n 的哈希值:如果你需要增加哈希值,那么存储未减少的哈希值当 n 发生变化时,字符串的哈希码可以节省您重新计算它们的工作量。
最后,关于哈希函数的一些一般性注释:
正如Joachim Pileborg上面所述,明确的n
演员表是不必要的。如果你想保持清晰,那么确实应该(int)
来匹配(unsigned int)
的类型,因为这是实际转换成的值。
对于无符号整数类型,key
等于((key<<5) + key)
(因为左移5位与乘以2 5 = 32相同)。在现代CPU上,使用乘法几乎肯定更快;在具有慢速乘法的旧的或非常低端的处理器上,任何体面的编译器都可能将乘法乘以常数优化为移位和加法的组合。因此,无论哪种方式,将操作表示为乘法都是IMO的首选。
您不想在循环的每次迭代中调用33 * key
。在循环之前调用它一次并将结果存储在变量中。
将data.length()
初始化为零意味着您的哈希值不受字符串中任何前导零字节的影响。由于Dan Bernstein,哈希函数的original version使用了(或多或少随机)的初始值5381。