KMP算法分析

根据博主July的https://blog.csdn.net/v_july_v/article/details/7041827所载,记录个人理解心得(红色部分为个人理解):

1.KMP算法流程

  假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
  1.如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;(当S[i]==P[j]时,说明模式串j前面的字符都与文本串i前面对应的字符匹配成功)

    

  2.如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。(next[j]为j前面字符所拥有的相同的最大前缀和后缀)
    即当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next值,即移动的实际位数为:j - next[j],且此值大于等于1

  如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。

int KmpSearch(char* s, char* p)
{
    int i = 0;
    int j = 0;
    int sLen = strlen(s);
    int pLen = strlen(p);
    while (i < sLen && j < pLen)
    {
        //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++    
        if (j == -1 || s[i] == p[j])
        {
            i++;
            j++;
        }
        else
        {
            //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]    
            //next[j]即为j所对应的next值      
            j = next[j];
        }
    }
    if (j == pLen)   //返回模式串在文本串的起始位置(当j==pLen时,说明已经匹配完成,所以其在文本串的起始点为i-j)
        return i - j;
    else
        return -1;
}

2. 前缀后缀最长公共元素长度

  公式:p0 p1 ...pk-1 pk = pj- k pj-k+1...pj-1 pj(左右两边原因下标相加为j)

  所以最大长度为k+1(因为是从0开始计数,到k结束)

  如:

  

  数组的next[i](0~i)值,表示的是当前字符之前的最大相同前后缀的值,如next[9]指的是ABCDEFGAB的最大相同前后缀;相当于最大相同前后缀平移1位,然后补-1;

3. next数组匹配

  匹配失配,j=next[j],模式串向右移动的位数为:j-next[j]。换言之,当模式串的后缀pj-k pj-k+1, ..., pj-1 跟文本串si-k si-k+1, ..., si-1匹配成功,但pj 跟si匹配失败时,因为next[j] = k,相当于在不包含pj的模式串中有最大长度为k 的相同前缀后缀,即p0 p1 ...pk-1 = pj-k pj-k+1...pj-1,故令j=next[j],从而让模式串右移j- next[j] 位,使得模式串的前缀p0 p1, ..., pk-1对应着文本串 si-k si-k+1, ..., si-1,而后让pk 跟si 继续匹配。如下图所示:

4 程序

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 
 5 void GetNext(char *str,int next[])
 6 {
 7     int j,length,k;
 8     next[0]=-1;
 9     
10     k=-1;
11     j=0;
12     length=strlen(str);
13     while(j<length-1)
14     {
15         if(k==-1 || str[k]==str[j])
16         {
17             j++;
18             k++;
19             if(str[j]!=str[k])
20             {
21                 next[j]=k;
22             }
23             else
24                 next[j]=next[k];
25         }
26         else
27         {
28             k=next[k];
29         }
30     }
31 }
32 
33 int KMP(char *s,char *t)
34 {
35     int next[10];
36     int len1,len2;
37     int i,j;
38     GetNext(t,next);
39     len1=strlen(s);
40     len2=strlen(t);
41     i=0;
42     j=0;
43     while(i<len1 && j<len2)
44     {
45         if(j==-1 || s[i]==t[j])
46         {
47             i++;
48             j++;
49         }
50         else
51             j=next[j];
52     }
53     if(j==len2)
54         return i-j;
55     else 
56         return -1;
57 }
58 
59 int main()
60 {
61     int i;
62     i=KMP("abcdefabcfed","abcf");
63     printf("%d ",i);
64 
65     system("pause");
66     return 0;
67 }

 

---------------------
感谢博主v_JULY_v
原文:https://blog.csdn.net/v_july_v/article/details/7041827 

posted @ 2019-01-06 11:34  dongry  阅读(186)  评论(0编辑  收藏  举报