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