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 程式
#include <stdio.h> #include <string.h> void Next(char*S,int *next)
{ int i=1; next[1]=0; int j=0; while (i<strlen(S))
{ if (j==0||S[i-1]==S[j-1])
{ i++; j++; next[i]=j; }else
{ j=next[j]; } } }
int KMP(char * S,char * s){ int next[10]; Next(s,next);//根據模式串T,初始化next陣列 int i=1; int j=1; while (i<=strlen(S)&&j<=strlen(s))
{ //j==0:代表模式串的第一個字元就和當前測試的字元不相等;S[i-1]==s[j-1],如果對應位置字元相等,兩種情況下,指向當前測試的兩個指標下標i和j都向後移 if (j==0 || S[i-1]==s[j-1])
{ i++; j++; } else
{ j=next[j];//如果測試的兩個字元不相等,i不動,j變為當前測試字串的next值 } } if (j>strlen(s))
{ //如果條件為真,說明匹配成功 return i-(int)strlen(s); } return -1; } int main()
{ int i=KMP("ababcabcacbab","abcac"); printf("%d",i); return 0; }
---------------------
感謝博主v_JULY_v
原文:https://blog.csdn.net/v_july_v/article/details/7041827