1. 程式人生 > 實用技巧 >KMP演算法初學

KMP演算法初學

具體講解https://blog.csdn.net/v_JULY_v/article/details/7041827

兩個概念得需要知道:

字首:指的是字串的子串中從原串最前面開始的子串,如abcdef的字首有:a,ab,abc,abcd,abcde
字尾:指的是字串的子串中在原串結尾處結尾的子串,如abcdef的字尾有:f,ef,def,cdef,bcdef

如果給定文字串S“BBCABCDABABCDABCDABDE”,和模式串P“ABCDABD”,

普通的方法就是暴力,從頭開始遍歷如果不匹配就讓字串向後平移一位,平且需要重新開始對比,重複此過程直到找到對應的字串,非常耗時。

KMP演算法不需要重新對比,只需要找到最長的公共前後綴然後將字首移至字尾,並且繼續從字串的當前位置開始比較,比如兩個串,主串abbababaabbab,模式串abbaa,我們從1開始遍歷(紅色表示不匹配,藍色表示最長公共字首字尾)

1.abbababaabbab

abbaa

第五位不同,且最長公共字首字尾長度為1,將模式串字首移至對應的字尾上,繼續從第五位開始比較不需要回溯,不斷的重複直到找到對應的子串:

abbababaabbab

abbaa

......(這是我理解的)

next 陣列各值的含義:代表當前字元之前的字串中,有多大長度的相同字首字尾。例如如果next [j] = k,代表j 之前的字串中有最大長度為k

的相同字首字尾。此也意味著在某個字元失配時,該字元對應的next 值會告訴你下一步匹配中,模式串應該跳到哪個位置(跳到next [j] 的位置)。如果next [j] 等於0或-1(0代表沒有,-1代表就不存在字首字尾),則跳到模式串的開頭字元,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某個字元,而不是跳到開頭,且具體跳過了k 個字元,next 陣列相當於“最大長度值” 整體向右移動一位,然後初始值賦為-1。


//優化過後的next 陣列求法 void GetNextval(char* p, int next[]) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { //p[k]表示字首,p[j]表示字尾 if (k == -1 || p[j] == p[k]) { ++j; ++k; //較之前next陣列求法,改動在下面4行 if (p[j] != p[k]) next[j] = k; //之前只有這一行 else //因為不能出現p[j] = p[ next[j ]],所以當出現時需要繼續遞迴,k = next[k] = next[next[k]] next[j] = next[k]; } else { k = next[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) return i - j; else return -1; }