KMP字符串模式匹配算法

关于字符串模式匹配,暂定目的是找到目标串当中的模式串出现的最先位置

本文参照了

http://kenby.iteye.com/blog/1025599

http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

两篇文章,这两篇文章详细介绍了KMP算法的原理和实现。

现在增加一点我的体会。

KMP算法相比原先的暴力算法来讲,不是一个字符一个字符的向前移动,而是根据模式串前缀数组跳跃式前进。

next[] 数组:用于表示在模式串的前n个字符当中前后对称的个数。

以000#xxx0000

为例:

算法需要:默认next[0]  = next[1] = 0;

next[2] = 1; next[3] = 2; next[4] = 0; next[5] = 0; next[6] =  0; next7] = 0; next[8] = 1; next9] = 2; next10] = 3; next[11] = 3;

现在讲述如何利用这些前缀数组进行匹配。

比如已经匹配了前n个字符,发现第n+1 个字符不匹配,那么将模式串向前移动 n - next[n] 个距离,然后从p[ next[n] ] 和 上次已经匹配的src[k] 进行匹配。

比如

 0000

 000#  已经匹配了前三个,第四个不匹配,那么移动 3 - next[3] = 1个位置,然后比较 p[next[3]] = p[2] 开始与 src[ ] 的后面进行比较

KMP字符串模式匹配算法_第1张图片

比如上图

已经匹配了6个字符

然后next[6] = 2 ,然后向前移动 6 - 2 = 4 个位置,然后

KMP字符串模式匹配算法_第2张图片

用p【next[6]】 = p[2] 与后面的数据进行比较。


下面讲述如何求解next[]数组

000#xxx0000

这个字符串

首先next[0] = next【1】 = 0;

    void compute_prefix(int *next, char *p)  
    {  
        int     i, n, k;  
      
        n = strlen(p);  
        next[1] = next[0] = 0;  
        k = 0;      /* 第i次迭代开始之前,k表示next[i-1]的值 */    
        for (i = 2; i <= n; i++) {  
            for (; k != 0 && p[k] != p[i-1]; k = next[k]);  
            if (p[k] == p[i-1]) k++;  
            next[i] = k;  
        }  
    }  

这个算法的正确性推一推就知道了

KMP算法C语言版本

#include<stdio.h>
#include<string.h>

void compute_prefix(int *next, char *p)
{
    int     i, n, k;

    n = strlen(p);
    next[1] = next[0] = 0;
    k = 0;      /* 第i次迭代开始之前,k表示next[i-1]的值 */
    for (i = 2; i <= n; i++) {
        for (; k != 0 && p[k] != p[i-1]; k = next[k]);
        if (p[k] == p[i-1]) k++;
        next[i] = k;
    }
}

void kmp_match(char* text,char* p,int* next)
{
    int m,n,q,s;
    m = strlen(p);
    n = strlen(text);
    s = 0;// s表示这次迭代从text的哪个字符开始比较
    q = 0;// q表示上一次迭代匹配了多少个字符
    while(s<n)
    {
        for(q=next[q];q<m&&p[q]==text[s];s++,q++);
        if(q==0)s++;
        else if(q==m){
             printf("pattern occurs with shift %d\n", s-m);
        }
    }

}
int main()
{
    int     next[101], n;
    char    *p = "000";
    char    *text = "000#xxx0000";

    compute_prefix(next, p);
    kmp_match(text, p, next);
    int i = 0;
    for(;i<4;i++)
    {
        printf("%d ",next[i]);
    }
    return 0;
}







你可能感兴趣的:(数据结构字符串)