C++ 拉宾卡普的滚动哈希
我试图实现Rabin Karp来查找子字符串;我被滚动的散列卡住了(试图使用C++ 拉宾卡普的滚动哈希,c++,c,string,algorithm,hash,C++,C,String,Algorithm,Hash,我试图实现Rabin Karp来查找子字符串;我被滚动的散列卡住了(试图使用 #定义MOD 100000007 无符号长滚动散列(const char*str) { 无符号长散列=0; 尺寸长度=strlen(strlen); 对于(inti=0,k=str_len-1;i
#定义MOD 100000007
无符号长滚动散列(const char*str)
{
无符号长散列=0;
尺寸长度=strlen(strlen);
对于(inti=0,k=str_len-1;i
只要我不引入任何余数操作,上面的代码就可以很好地工作;一旦我取消注释我的%
操作,事情就会崩溃,我从滚动散列的更改中得到的答案将不等于第二次打印时得到的答案。janisz的回答:
在janisz的回答中,更改哈希生成器的建议在添加新字符时使剩余的字符起作用,而在删除旧字符时则不起作用。
注意:我使用自己的
pow
函数来处理无符号long-long
哈希生成器代码是错误的。应该是
hash = (hash*257 + str[i]) % MOD;
和unncomentold\u hash=old\u hash%MOD代码>。还要更改从以前的哈希生成新哈希的方式
(old_hash - to_delete_char * pow(257, str_len-1)) % MOD;
看看你的代码。前两行非常好。循环中发生了什么。
首先,你正在做尽可能多的乘法运算。在我的方法中,我使用计算哈希,因为哈希是多项式
为什么它在没有模量和没有模量的情况下工作。我认为这是一个巧合,因为您用8个字符溢出整数(log(2^64)/log(257)=8)
现在,删除字符有什么问题<代码>删除字符*pow(257,str_len)代码>应该是以删除字符*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;
}
#包括
#包括
#包括
#包括
#定义MOD 787
无符号长功率(整数x,整数y)
{
无符号长ret=1;
对于(int i=0;i注释行有何错误?%
实际上表示模数。@帕莱克:请检查编辑的问题。(旁注:%really表示余数,而不是模数)()修复了散列生成器并取消了mod行的注释,修复了向字符串添加新字符的问题;但您能解释一下以前的代码有什么问题吗?至于删除字符,这不起作用。@AdelQodmani现在尝试删除。问题出在pow(257,str_len)
。我会在回答中解释。你是指霍纳的方法,而不是赫隆方法。也称为霍纳方案。@AdelQodmani它是否因任何输入而损坏?你能发布更多的代码吗。我想可能与溢出有关issue@janisz我对这个问题进行了一些编辑,以反映我到底在做什么;到目前为止,你的建议对删除字符不起作用另一件事,不是做了尽可能多的乘法是一件好事吗?是的,速度慢;但它不会降低碰撞的机会吗?或者我弄错了什么?是的,它对于任何输入都是坏的。
#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;
}