Rabin Karp算法用于大字符串

时间:2016-05-10 23:00:24

标签: algorithm modulus rabin-karp

我为子串搜索编写了一个简单的Rabin-Karp算法的逐步实现,它似乎工作正常,直到哈希变得大于模数,然后它出错...

这是代码,很简单:

typedef long long ll;

#define B 257
//base
#define M 2147483647
//modulus

//modulus for positive and negative values
ll mod(ll a){
    return (a % M + M) % M;
}

//fast way to calculate modular power
ll power(ll n, ll e){
    ll r = 1;
    for(; e > 0; e >>= 1, n = (n*n) % M)
        if(e&1) r = (r * n) % M;
    return r;
}

//function to calculate de initial hash
//H(s) = s[0] * B^0 + s[1] * B^1 + ...
ll H(char sub[], int s){
    ll h = 0;
    for(ll i = 0; i < s; i++)
        h = mod(h + mod(power(B, i) * sub[i]));
    return h;
}

//brute force comparing when hashes match
bool check(char text[], char sub[], int ini, int s){
    int i = 0;
    while(text[ini + i] == sub[i] && i < s) i++;
    return i == s;
}

//all together here
void RabinKarp(char text[], char sub[]){
    int t = strlen(text), s = strlen(sub);
    ll hs = H(sub, s), ht = H(text, s);
    int lim = t - s;

    for(int i = 0; i <= lim; i++){
        if(ht == hs)
            if(check(text, sub, i, s))
                printf("MATCH AT %d\n", i);           

        ht -= text[i];      
        ht /= B;            
        ht = mod(ht + power(B, s - 1) * text[i + s]);

        //we had    text[i] * B^0 + text[i+1] * B^1 + ... + text[i + len - 1] * B^(len-1)

        //then    text[i+1] * B^1 + text[i+2] * B^2 + ... + text[i + len - 1] * B^(len-1)
        //then    text[i+1] * B^0 + text[i+2] * B^1 + ... + text[i + len - 1] * B^(len-2)
        //finally we add a new last term text[i + len] * B^(len-1)

        //so we moved the hash to the next position
    }
}



int main(){
    char text[] = "uvauvauvaaauva";
    char sub[] = "uva";
    char sub2[] = "uvauva";
    RabinKarp(text, sub);
    printf("----------------------------\n");
    RabinKarp(text, sub2);
}

问题在于,在我取模数之后,哈希值可以变成一个小数,然后,当我为它添加一些重要因素时,哈希值可能不匹配,即使它们应该也是如此。

例如:xcc中的abc

当我接受abc和xab的散列时,假设它们都比模数大,所以它们在模数运算后变小。

然后,当我删除'x'并添加'c'因子时,总和可以小于模数,但仍然很大,所以它不匹配。

我该如何克服这个问题?

1 个答案:

答案 0 :(得分:2)

ht / = B; 不可信。首先是因为你在做算术模型M,而模块的等效除法与标准的不同。其次,因为你应该期望x和x + M的答案相同,但事实并非如此。

你有文字[i] * B ^ 0 + text [i + 1] * B ^ 1 + ... + text [i + len - 1] * B ^(len-1)

如果您使用

text [i] * B ^(len-1)+ text [i + 1] * B ^(len - 2)+ ... + text [i + len - 1] * B ^ 0

你可以减去文本[i] * B ^(len-1)然后乘以B而不是