拉宾·卡普的滚动散列
Rolling hash in Rabin-Karp
我正在尝试实现用于查找子字符串的Rabin Karp;我陷入了滚动散列(试图使用维基百科上建议的公式)。
#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("%llun", rolling_hash("TestString"));
printf("%llun", 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%llun", old);
return 0;
}
只要我不引入任何余数运算,上面的代码就可以很好地工作;一旦我取消对%
操作的注释,事情就会崩溃,我从滚动哈希的更改中得到的答案将不等于第二次打印时打印的答案
janisz的回答:
在janisz的回答中,更改哈希生成器的建议使剩余部分在添加新字符时可以工作,但在删除旧字符时不能工作
注意:我使用自己的pow
函数来处理unsigned long long
哈希生成器代码错误。应该是
hash = (hash*257 + str[i]) % MOD;
和未出现的CCD_ 4。还可以更改从以前的生成新哈希的方式
(old_hash - to_delete_char * pow(257, str_len-1)) % MOD;
看看你的代码。前两行非常好。循环中发生了什么。首先,你要做尽可能多的乘法运算。在我的方法中,我使用了计算哈希的Horner方案,因为哈希是一个多项式。
为什么它在没有模量和没有模量的情况下工作。我认为这是一个巧合,因为你溢出了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: %llun", rolling_hash(input));
printf("Expected: %llun", 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: %llun", old);
return 0;
}
相关文章:
- 欧拉项目#8答案是大以获得有效答案
- 使用一个考虑到std::map中键值的滚动或换行的键
- QScrollArea:由垂直滚动条引起的水平滚动条
- 跟踪滚动条上的鼠标事件
- 内存错误低于在C++年实现埃拉托色尼筛分时的预期
- 如何在音频处理中使用超能力时间拉伸类
- 如何在不使用滚动条的情况下使视图更改
- 如何为对象生成滚动效果?
- 如何模拟不同边数的骰子滚动?
- 单元测试欧拉到四元数实现失败
- 米勒-拉宾测试不适用于252097800623
- 使用拉宾·卡普进行模式搜索
- 确定性米勒-拉宾实现
- 拉宾·卡普的滚动散列
- 米勒-拉宾素数测试 FIPS 186-3 实现
- 使用水平滚动条手动设置 MFC CComboBox 下拉列表高度
- 拉宾-卡普算法
- 米勒-拉宾素性测试给出了错误的答案
- 128位米勒·拉宾质数测试
- 卡普·拉宾的素数和块长度