假設現在有abcadabcdabcab這樣乙個字串(字元個數為n),abcab這樣乙個模式串(字元個數為m),要求找到完全匹配時首字母的位置。第一眼看上去,我們想到了暴力求解的方法,從被匹配串的第乙個位置開始與模式串相比較,如果成功,則輸出首字母的位置,否則從第二個位置重新開始比較。依次進行下去,直到找到結果或超過第n-m個位置時停止。顯然得知,時間複雜度為o(n
2)
o(n^2)
o(n2)。
然而這樣大的時間複雜度完全不能滿足我們的要求,我們要尋找一種更為快速的方法。
當然,一種更快的演算法也不是毫無根據的就出現的,它的創始人絞盡腦汁,想到我們每次可不可以不推進乙個位置而是推進更多的位置呢?想著想著,kmp演算法出現了。
首先,要了解兩個概念:「字首"和"字尾」。 "字首"指除了最後乙個字元以外,乙個字串的全部頭部組合;"字尾"指除了第乙個字元以外,乙個字串的全部尾部組合。
kmp演算法最重要的乙個思想就是,利用已知資訊來實現更快的查詢速度。具體怎麼實現的呢?看圖更直觀。
abca
dabcdabcab
abca
b看到沒,在b處失配了,模式串不高興了,它正打算往後走一步,被匹配串毅然決然地告訴它,你個傻子,你直接走到我的下乙個a處就行了,中間的再走也匹配不了。即失配時,模式串向右移動的位數為:已匹配字元數 - 失配字元的上一位字元所對應的最大長度值,如下圖:
abca
dabcdabcab
abcab
證明過程我在這裡就不寫了,你只要知道,每次移動,直接移動到與字首對稱的字尾位置。這時候,我們需要知道模式串從左往右不斷變長的子串的對稱前字尾的字元個數。如下圖:ab
cab0
1234
0001
2以上的表的第三行即為kmp演算法裡面提到的next陣列了。說實話,肉眼一看就能的出來,可是,怎樣才能寫一段簡潔的**來實現呢?
假設我們已經走到了4這個位置,我們要求出next[4],我們只需要看一下str[4]和str[1]是不是相等,如果一樣,next[4]=next[3]+1,即此時最大前字尾長度k+1。否則,進入迴圈,直到最大前字尾長度k變成0或str[4]與str[k]相等。**如下:
完整的kmp演算法**如下:void
makenext
(const
char p,
int next)
next[q]
= k;
}}
部分內容來自#include
#include
void
makenext
(const
char p,
int next)
next[q]
= k;}}
intkmp
(const
char t,
const
char p,
int next)
if(q == m)}}
intmain()
;char t=
"ababxbababcadfdsss"
;char p=
"abcdabd"
;printf
("%s\n"
,t);
printf
("%s\n"
,p )
;// makenext(p,next);
kmp(t,p,next)
;for
(i =
0; i <
strlen
(p);
++i)
printf
("\n");
return0;
}
對KMP演算法的理解
kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...
對KMP演算法的理解
kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...
對KMP演算法的理解
kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...