KMP算法初解及代码

    假设有字符串s1和字符串s2,长度分别为n和m。在求解s2是否为s1的子串这个问题中,可称s1是匹配串,称s2为模式串。KMP算法是一个复杂度为O(n+m)的算法。

    在KMP算法中,有很多定义next数组的方式,并文介绍其中一种。

    next数组采用以下定义。若next[j]==k,则k满足以下条件的最大值;s2[0..k-1]与s2[j-k..j-1]相同,且s2[k]与s2[j]不同。若不存在这样的k,则next[j]=-1.即k满足s2的长度为k的前缀是s2的长度为j的前缀的后缀,且s2[j]!=s2[k]的最大值。

    形象地说,KMP的匹配过程就好像是把s2放在s1的下边,匹配失败时直接将s2右移。

c语言代码:

#include <stdio.h>
#include <stdlib.h>


const int INF=~0u >>1;
int a[1000001],b[10001],next[10001];


int kmp(int s1[], int s2[], int next[]){


    int i, j=0, k=-1, ans=0;
    next[0]=-1;
    while(s2[j] !=INF){//求next数组 最大相同的前后缀长度为k
        while(k !=-1 && s2[j] !=s2[k])
            k=next[k];
        j++;
        k++;
        if(s2[j] !=s2[k])
            next[j]=k;
        else
            next[j]=next[k];
    }
    i=j=0;
    while(s1[i] !=INF){
        if(j !=-1 && s2[j] ==INF)
            return i-j+1;
        while(j !=-1 && s1[i] !=s2[j])
            j=next[j];
        i++;
        j++;
    }
    if(s2[j] == INF)
        return i-j+1;
    return -1;
}


int main()
{
    int t, n, m, i;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        for(i=0; i<n; i++) scanf("%d", &a[i]);
        for(i=0; i<m; i++) scanf("%d", &b[i]);
        a[n]=b[m]=INF;
        printf("%d\n", kmp(a, b, next));
    }
    for (i = 0; i < m; ++i)
    {
        printf("%d ",next[i]);
    }
    return 0;
}

    哈哈,不太好理解吧,下面有一个我自认为更好理解的代码:

#include<stdio.h>
#include<string.h>
void makeNext(const char P[],int next[])
 {
    int q,k;
     int m = strlen(P);
    next[0] = 0;
    for (q = 1,k = 0; q < m; ++q)
    {
        while(k > 0 && P[q] != P[k])
            k = next[k-1];
        if (P[q] == P[k])
        {
            k++;
        }
        next[q] = k;
    }
}


 void kmp(const char T[],const char P[],int next[])
 {
    int n,m;
    int i,q;
     n = strlen(T);
     m = strlen(P);
     makeNext(P,next);
    for (i = 0,q = 0; i < n; ++i)
     {
        while(q > 0 && P[q] != T[i])
            q = next[q-1];
        if (P[q] == T[i])
         {
             q++;
        }
         if (q == m)
         {
             printf("Pattern occurs with shift:%d\n",(i-m+1));
        }
    }
 }


int main()
 {
    int i;
    int next[20]={0};
    char T[] = "ababxbababcadfdsss";
    char P[] = "abcdabd";
    printf("%s\n",T);
    printf("%s\n",P );
    makeNext(P,next);
    kmp(T,P,next);
    for (i = 0; i < strlen(P); ++i)
    {
        printf("%d ",next[i]);
    }
    printf("\n");


    return 0;
}

猜你喜欢

转载自blog.csdn.net/yige__cxy/article/details/81059771