快速模式匹配演算法(KMP)

2021-07-04 19:34:21 字數 2558 閱讀 8261

恐怕現在用過電腦的人,一定都知道大部分帶文字編輯功能的軟體都有乙個快捷鍵ctrl+f 吧(比如word)。這個功能主要來完成「查詢」,「替換」和「全部替換」功能的,其實這就是典型的模式匹配的應用,即在文字檔案中查詢串。

1.模式匹配

模式匹配的模型大概是這樣的:給定兩個字串變數s和p,其中s成為目標串,其中包含n個字元,p稱為模式串,包含m個字元,其中m<=n。從s的給定位置(通常是s的第乙個位置)開始搜尋模式p。如果找到,則返回模式p在目標串中的位置(即:p的第乙個字元在s中的下標)。如果在目標串s中沒有找到模式串p,則返回-1.這就是模式匹配的定義啦,下面來看看怎麼實現模式匹配演算法吧。

2.樸素的模式匹配

3.快速模式匹配演算法(kmp)

樸素的模式匹配效率不高的主要原因是進行了重複的字元比較。下一次比較和上一次比較沒有任何的聯絡,是樸素模式匹配的缺點,其實上一次比較的比較結果是可以利用的,這就產生了快速模式匹配。在樸素的模式匹配中,目標串s的下標移動是一步一步的,這其實並不好,移動步數沒有必要為1。

現在不妨假設,當前匹配情況是這樣的:s0 …… st st+1 …… st+j  與 p0 p1…… pj ,現在正在嘗試匹配的字元是st+j+1和pj+1,並且st+j+1 != pj+1,言外之意就是說st st+1……st+j和p0 p1……pj是完全匹配的。那麼這個時候,s中下一次匹配開始位置應該是什麼呢??按照樸素的模式匹配,下次比較應該從st+1開始,並且令st+1和p0比較,但是在快速模式匹配中並不是這樣,快速模式匹配選擇st+j+1和pk+1比較,k是什麼呢?k是這樣的乙個值,使得p0 p1……pk 和 pj-k pj-k+1……pj完全匹配,不妨設k=next[j],因此p0 p1……pk和st+j-k st+j-k+1 ……st+j完全匹配。那麼下一次要進行匹配的兩個字元應為st+j+1和pk+1。s和p都沒有回溯到下標0在進行比較,這就是kmp之所以快的原因啦。

現在關鍵問題來了,這個k怎麼能得到呢?如果得到這個k值複雜度高,那這個思路就不好了,其實這個k呢,只和模式串p有關係,並且要求m個k,k = next[j],因此只要算一次儲存到next陣列中就可以了,並且時間複雜度和m有關係(線性關係)。看看具體怎麼求next陣列的值,即求k。

用歸納法求next:設next(0) = -1,若已知next(j) = k,欲求得next[j+1]。

(1)如果pk+1 = pj+1,顯然next[j+1] = k+1.如果pk+1 != pj+1,則next[j+1] < next[j],於是尋找h < k 使得p0 p1……ph=pj-h pj-h+1……pj=pk-h pk-h+1……pk。也就是說h = next(k);看出來了吧,這是個迭代的過程。(也就是以前的結果對求以後的值有用)

(2)如果不存這樣的h,說明p0 p1……pj+1中沒有前後相等的子串,因此next[j+1] =-1.

(3)如果存在這樣的h,繼續檢驗ph和pj是否相等。知道找到這中相等的情況,或者確定為-1求next[j+1]的過程結束。

看看實現的**:

int next[20] =;

//注意返回結果是乙個陣列next,儲存m個k值得地方,即若next[j]=k

//則str[0]str[1]…str[k] = str[j-k]str[j-k+1]…str[j]

//這樣當des[t+j+1]和pat[j+1]匹配失敗時,下乙個匹配位置為des[t+j+1]和next[j]+1

void next(char str,int

len)

if(str[j] == str[i+1

])

else

}}

現在有了next陣列儲存的k值,就可以實現kmp演算法了:

//

des是目標串,pat是模式串,len1和len2是串的長度

int kmp(char des,int len1,char pat,int

len2)

else

else}}

if(p < len2)//

整個過程匹配失敗

return s-len2;

}

時間複雜度:

對於next函式近似接近o(m),kmp演算法的時間複雜度為o(n),所以整個演算法的時間複雜度為o(n+m)

空間複雜度:

多引入了o(m)的空間複雜度。

4.應用kmp的一道面試題

給定兩個字串是s1和s2,要判定s2是否能夠被s1做迴圈移位得到的字串包含。例如s1=aabcd,s2 =cdaa,返回true,因為s1迴圈移位可以變成cdaab。給定s1=acbd和s2=acbd則返回false。

分析:不難發現對s2移位得到的字串都將是字串s1s1的子串,如果s2可以有s1迴圈移位得到,那麼s2一定是s1s1的子串,這時kmp演算法是不是就很管用了呢。

思考:有沒有比kmp更好的思路呢??

KMP演算法(快速模式匹配演算法)c語言

傳統的bf演算法容易理解且實現,但是查詢效率不高,kmp本身不複雜,關鍵在於next陣列的構建,但網上絕大部分的文章把它講混亂了。下面,我們闡述kmp的流程 步驟 next 陣列的簡單求解 遞推原理 求解,希望更多的人不再被kmp折磨或糾纏,不再被一些混亂的文章所混亂。kmp演算法的核心,是乙個被稱...

模式匹配 KMP演算法

字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...

模式匹配KMP演算法

前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...