【问题标题】:c- Karp-Rabin rolling hash - skip and append partsc- Karp-Rabin 滚动哈希 - 跳过和附加部分
【发布时间】:2021-07-03 09:49:23
【问题描述】:

我需要一些关于我的 Karp-Rabin 算法的特定部分的帮助。 我要做的是使用固定的sliding window 和单独的appendskip 部分来实现版本。 Sliding window 工作得很好。当我尝试将单体 sliding window 拆分为 appendskip 部分时,就会出现问题。 Append 似乎工作正常,但 skip 是最近几天让我头疼的东西。

问题 - 我正在滑过包含几个订阅模式实例的字符串。 Sliding window 检测到它,但没有检测到其他两个。

这个想法是 RH 结构保存 (base ^ window size) mod prime number (b2wmod) 的预计算值,因此我可以删除字符串的前导字符.在所有appendskip 之后,此值会随着窗口大小的变化而变化。为了减少b2wmod 的值,乘法逆用于不处于模删除的情况(基本模模值的逆)。它也是预先计算的。

以下是我感兴趣的代码部分。我不发布整个代码以免您阅读所有内容,但如果需要可以上传。乘法逆似乎计算正确,但我也可以上传代码。

不胜感激!提前谢谢!

void
append_to_rh(RH rh)
{
    uint64_t hash    = rh->hash;
    uint64_t base    = rh->base;
    uint64_t mod     = rh->mod;
    uint64_t b2wmodm = rh->b2wmodm;
    char     new     = rh->new;
    
    hash             = ( hash * base + new ) % mod;    
    b2wmodm          = ( b2wmodm * base ) % mod;
    
    rh->hash         = hash;
    rh->b2wmodm      = b2wmodm;
}

void
skip(RH rh)
{
    uint64_t hash       = rh->hash;
    uint64_t base       = rh->base;
    uint64_t mod        = rh->mod;
    uint64_t b2wmodm    = rh->b2wmodm;
    uint64_t m_inv      = rh->m_inv;
    char     old        = rh->old;
    uint64_t correction = old * mod;
   
    b2wmodm = ( b2wmodm * (m_inv % mod) ) % mod;
    hash    = ( hash - old * b2wmodm + correction ) % mod;

    rh->hash    = hash;
    rh->b2wmodm = b2wmodm;
}

void
slide_window(RH rh)
{
    uint64_t base    = rh->base;
    uint64_t mod     = rh->mod;
    uint64_t hash    = rh->hash;
    uint64_t b2wmodm = rh->b2wmodm;
    char old = rh->old;
    char new = rh->new;

    hash     = ( hash * base - old * b2wmodm + new ) % mod;
    rh->hash = hash;
}

【问题讨论】:

    标签: c algorithm rabin-karp


    【解决方案1】:

    您的 appendskip 函数工作正常。这是我用于测试的示例代码

    #include <string>
    #include <cassert>
    
    typedef long long ll;
    
    ll hash, b2wmodm, base, inv_base, mod;
    
    // fast exponentiation, for calculating inv_base
    ll exp(ll a, ll b){
        ll ans = 1;
        while (b){
            if (b&1){
                ans *= a;
                ans %= mod;
            }
            a *= a;
            a %= mod;
            b >>= 1;
        }
        return ans;
    }
    
    // calculates expected hash of the string
    ll expected_hash(std::string s) {
        ll result = 0;
        ll multiplier = 1;
        for (int i = s.length()-1; i >= 0; i--) {
            result += s[i] * multiplier % mod;
            result %= mod;
            multiplier = multiplier * base % mod;
        }
        return result;
    }
    
    // same as your append and skip functions
    void append_to_rh(ll newc) {
        hash = (hash * base + newc) % mod;
        b2wmodm = (b2wmodm * base) % mod;
    }
    
    void skip(ll old) {
        ll correction = old * mod;
    
        b2wmodm = (b2wmodm * (inv_base % mod)) % mod;
        hash = (hash - old * b2wmodm + correction) % mod;
    }
    
    int main() {
    
        base = 29;
        mod = 1000000007;
    
        hash = 0;
        b2wmodm = 1;
        inv_base = exp(base, mod-2);
    
        srand(time(nullptr));
        std::string s;
        for (int i = 0; i < 2000; i++) {
            if (i < 1000 || rand()%2) {
                char newchar = rand()%26 + 'a';
                s += newchar;
                append_to_rh(newchar);
                assert(expected_hash(s) == hash);
            } else {
                char oldchar = s[0];
                s = s.substr(1, s.length());
                skip(oldchar);
                assert(expected_hash(s) == hash);
            }
        }
    }
    

    我猜你代码的其他部分会导致问题。也许您正试图跳过一个空窗口,或者您可能使用了非主要模式。

    【讨论】:

    • 尊敬的先生,请接受我最深切的感谢!这确实是我的素数中的一个问题,我认为我检查了数百万次。这个问题让我非常绝望,所以我现在真的欠你一点人情来检查这个问题)
    猜你喜欢
    • 1970-01-01
    • 2013-12-23
    • 2017-07-27
    • 1970-01-01
    • 2018-11-22
    • 2023-03-09
    • 2012-01-18
    • 1970-01-01
    • 2014-02-21
    相关资源
    最近更新 更多