串-模式匹配-MP算法

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83212383

之前学习了KMP算法,现在学习一下它的弱化版:MP算法。

为啥还要学习它呢?因为它是接下来要学习的AC-自动机的基础。

输入:主串S,子串T

输出:主串中子串第一次出现的位置(0-length(S-1))。匹配不到不输出.

样例:

S:ababcabcacbab

T:abcac

运行结果:

算法思想:

假定在匹配的过程中正在比较文本串*位置的字符和模板串abbaaba的最后一个字符。发现二者不同(称为失配),这时,朴素算法会把模板串后移一位,重新比较abbaaba的第一个字符和文本串!!位置的字符。

扫描二维码关注公众号,回复: 3690245 查看本文章

MP算法认为,既然!!位置已经比较过一次,就不应该再比一次了,事实上,我们已经知道灰色部分就是abbaab,应该可以直接利用模板串本身的特性判断出右移一位一定不是匹配。同理,右移两位或者三位也不行,但是右移四位是有可能的。这个时候,需要比较*处的字符刚和abbaaba的第三个字符。

下面其中编号为i的结点表示已经匹配了i个字符,匹配开始时当前状态是0,成功匹配时状态加1(表示多匹配一个字符)

而失配时沿着失配边走。用失配函数f[i]表示状态i失配时应转移到新状态,要特别注意的是f[0]=0.

void find(char *T, char *P, int *f)
{
    int n, m, i, j;

    n = strlen(T);
    m = strlen(P);
    getFail(P, f);
    j = 0;                             //当前结点编号,初始为0号结点
    for(i = 0; i < n; i++)             //文本串当前指针
    {
        while(j && P[j] != T[i])       //顺着失配边走,直到可以匹配
            j = f[j];
        if(P[j] == T[i])
            j++;
        if(j == m)
            printf("%d\n", i-m+1);     //找到了
    }
}

算法分析:

每次j++的时候会伴随一次i++,而每次j=f[j]的时候j至少会减1.最坏情况下j增加了n次,因此j=f[j]的次数不会超过n。

因此总时间复杂度O(n)。

状态转移图的构造是MP算法的关键。也是它最巧妙的地方。

算法的思想是:用自己匹配自己。根据f[0],f[1],f[i-1]递推f[i]。

//状态转移图,用自己匹配自己,用f[0],f[1]..f[i-1] 递推f[i].
void getFail(char *P, int *f)
{
    int m, i, j;

    f[0] = 0;
    f[1] = 0;                               //递推边界初值
    m = strlen(P);
    for(i = 1; i < m; i++)
    {
        j = f[i];
        while(j && P[i] != P[j])
            j = f[j];
        f[i+1] = (P[i] == P[j]) ? (j+1):0;
    }
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83212383