我正在尝试实现Rabin来查找子字符串;我陷入了滚动散列(试图使用维基百科中提出的公式)中。
#define MOD 1000000007
unsigned long long rolling_hash(const char *str)
{
unsigned long long hash = 0;
size_t str_len = strlen(str);
for(int i = 0, k = str_len -1; i < str_len; i++, k--) {
hash = hash + str[i] * pow(257, k);
// hash = hash % MOD;
}
return hash;
}
int main(void)
{
printf("%llu\n", rolling_hash("TestString"));
printf("%llu\n", rolling_hash("estStringh"));
unsigned long long old = rolling_hash("TestString");
// Add a character to the end
// since the last char in old was multiplied by 1, now multiply it by
// the base and then add the _new_ character to the end
old = old * 257 + 'h';
//old = old % MOD;
// Remove a char from the start
// Simply, remove the hash value of the first character
old = old - 'T' * pow(257, 10);;
printf("\n%llu\n", old);
return 0;
}只要我不引入任何剩余的操作,上面的代码就能很好地工作;一旦我取消了对我的%操作的注释,事情就会崩溃,我从滚动散列的更改中得到的答案将不等于第二次打印所打印的结果。
janisz的回答:
修改散列生成器(如janisz中的答案)的建议使其余部分在添加新字符时起作用,而在删除旧字符时则不起作用。
注意:,我正在使用自己的pow函数来处理unsigned long long
发布于 2013-12-05 22:59:52
哈希源程序代码是错误的。它应该是
hash = (hash*257 + str[i]) % MOD;和不友好的old_hash = old_hash % MOD;。还可以更改以前生成新哈希的方式。
(old_hash - to_delete_char * pow(257, str_len-1)) % MOD;看看你的代码。前两行非常好。循环中发生了什么。首先,你正在做尽可能多的乘数。在我的方法中,我使用了计算散列的霍纳方案,因为散列是一个多项式。
为什么它工作时,没有模数,但没有。我认为这是一个巧合,因为溢出整数有8个字符(log(2^64)/log(257) = 8)。
现在移除字符有什么问题。to_delete_char * pow(257, str_len);应该是to_delete_char * pow(257, str_len-1);索引,应该从0开始,而不是从1开始,以获取生成器。
编辑:,我认为问题出在pow函数中。正如我上面所写的,它溢出了8个字符。在你的例子中,你有10,所以它不能工作。
编辑:--原来添加和删除字符必须作为一个操作来完成。可能是因为等价物,但我不确定。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MOD 787
unsigned long long pow(int x, int y)
{
unsigned long long ret = 1;
for (int i=0;i<y;i++)
ret = (ret*x)%MOD;
return ret;
}
unsigned long long rolling_hash(const char *str)
{
unsigned long long hash = 0;
size_t str_len = strlen(str);
for(int i = 0, k = str_len -1; i < str_len; i++, k--) {
hash = hash + (str[i] * pow(257, k))%MOD;
hash = hash % MOD;
}
return hash;
}
int main(void)
{
char input[] = "TestString";
printf("Input: %llu\n", rolling_hash(input));
printf("Expected: %llu\n", rolling_hash("estStringh"));
unsigned long long old = rolling_hash(input);
// Add a character to the end
// and Remove a char from the start
unsigned long long h = (input[0] * pow(257, strlen(input)))%MOD;
old = ((old * 257) + 'h' - h) % MOD;
printf("Actual: %llu\n", old);
return 0;
}https://stackoverflow.com/questions/20412405
复制相似问题