以前看過kmp演算法,當時接觸後總感覺好深奧啊,抱著資料結構的數啃了一中午,最終才大致看懂,後來提起kmp也只剩下「奧,它是做模式匹配的」這點乾貨。最近有空,翻出來演算法導論看看,原來就是這麼簡單(先不說程式實現,思想很簡單)。
模式匹配的經典應用:從乙個字串中找到模式字串的位置。如「abcdef」中「cde」出現在原串第三個位置。從基礎看起
樸素的模式匹配演算法
a:abcdefg b:cde
首先b從a的第一位開始比較,b++==a++,如果全部成立,返回即可;如果不成立,跳出,從a的第二位開始比較,以此類推。
/*思路樸實無華,十分有效,但是時間複雜度是o(mn),m、n分別是字串和模式串的長度。模式匹配是乙個常見的應用問題,用的廣了,就有人想法去優化了。rabin-karp演算法、有限自動機等等,前仆後繼,最終出現了kmp(knuth-morris-pratt)演算法。*侯凱,2014-9-16
*功能:模式匹配 */
#include
#include
using
namespace
std;
int index(char *a,char *b)
}if(b[patlen]=='\0'
)
tarindex++;
}return -1;}
intmain()
kmp演算法
優化的地方:如果我們知道模式中a和後面的是不相等的,那麼第一次比較後,發現後面的的4個字元均對應相等,可見a下次匹配的位置可以直接定位到f了。說明主串對應位置i的回溯是不必要的。這是kmp最基本最關鍵的思想和目標。
再比如:
由於abc 與後面的abc相等,可以直接得到紅色的部分。而且根據前一次比較的結果,abc就不需要比較了,現在只需從f-a處開始比較即可。說明主串對應位置i的回溯是不必要的。要變化的是模式串中j的位置(j不一定是從1開始的,比如第二個例子)
j的變化取決於模式串的前字尾的相似度,例2中abc和abc(靠近x的),字首為abc,j=4開始執行。
j是前一次執行的模式子串(前幾個,上例為6)中字首的個數+1;它與模式字串中從前向後的字首和從後向前的字尾的相同子串是有關係的,因為下次這部分相同的字首就會移動到這部分字尾的位置,因為如果移動到字尾的前面位置,看圖:
所以如果這次是j,下次的位置應該就是j前面的子串的最大字首的長度+1,用這個新的位置再和原字串的i位置進行比較就很幸福了。
這次是j,下次到底是多少呢,這就涉及到怎麼計算的問題了?其實只看模式串我們就可以構建出這個j->x的關係,關係稱為字首函式,結果儲存在陣列中,稱為字首陣列。
偽**:
compiter-prefix-function(p)使用字首陣列可很快地實現模式匹配,程式匹配字串中模式出現的所有位置。mpi[1]k
for q
to m
dowhile k>0 and p[k+1]!=p[q]
do k
字首的字首...
if p[k+1]==p[q]
then k
pi[q]
return pi
kmp-matcher(t, p)nmpiqfor i
to n
dowhile q>0 and p[q+1]!=t[i]
do q
字首的字首...
if p[q+1]==t[i]
then q
if q==m
then print 「pattern occurs with shift」i-m
q這兩段**思想完全相同,如果和字首不同就比較字首的字首…,比較巧妙。如果kmp有難理解的地方,估計就是這段偽碼的了。
kmp演算法的時間複雜度為o(n+m)。
這裡需要強調一下,kmp演算法的僅當模式與主串之間存在很多部分匹配情況下才能體現它的優勢,部分匹配時kmp的i不需要回溯,否則和樸素模式匹配沒有什麼差別。
簡單有效的kmp演算法
以前看過kmp演算法,當時接觸後總感覺好深奧啊,抱著資料結構的數啃了一中午,最終才大致看懂,後來提起kmp也只剩下 奧,它是做模式匹配的 這點乾貨。最近有空,翻出來演算法導論看看,原來就是這麼簡單 下不說程式實現,思想很簡單 模式匹配的經典應用 從乙個字串中找到模式字串的位置。如 abcdef 中 ...
KMP演算法的簡單理解
對於串的匹配,較為簡單的有bf演算法,但這種方法的可用性卻較差。因為在每次不匹配的時候,主串 m位 和子串 n位 都會回溯,有一種最壞的情況就是,主串每前進一位,都在n次匹配後失敗然後回溯,如 主串 aaaaaaaaaaaaaaaaaaaaab 子串 aab 這樣會導致bf演算法的時間複雜度大大提公...
kmp演算法 簡單易懂
kmp字串 給定乙個模式串s,以及乙個模板串p,所有字串中只包含大小寫英文本母以及阿拉伯數字。模板串p在模式串s中多次作為子串出現。求出模板串p在模式串s中所有出現的位置的起始下標。輸入格式 第一行輸入整數n,表示字串p的長度。第二行輸入字串p。第三行輸入整數m,表示字串s的長度。第四行輸入字串s。...