1. 程式人生 > >KMP演算法分析

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