我從對暴力匹配演算法的優化角度出發,理解和構造出kmp演算法。
模式匹配問題中,有主串,子串,模式串,字首,字尾,部分匹配值等等概念。教材往往」反著來「,先有解決方案和概念,再強行說」啊,就是這樣子的「。但我們都應該清楚,概念是輔助思考,輔助解決遇到的問題的。
假設我們已經弄懂了暴力匹配解決模式匹配的方法,那麼也就清楚主串、子串和模式串的概念。
現在,想辦法對暴力匹配演算法進行優化。所謂」暴力匹配「,就是它窮舉遍歷了主串的」子串空間「,即每乙個子串都去對比一次。但是很多情況,子串部分匹配了模式串,」眼看著就要匹配成功了「,卻失配了。針對這些情況,暴力匹配演算法都是採取直接復位主串指標,」就好像一切都沒發生過「。
同樣極端的,我們也可以採取」不後悔「的策略。即下圖的」簡單策略「,直接跳過那些被部分匹配的字元。
但很不幸,這樣做存在」錯過對的子串「的可能性。
這讓我們反思:為什麼部分匹配失敗的字元卻組成了匹配成功的子串?
這個例子幫助我們發現了前面的斷言太過於決定,只有那些沒有」內在模式「的部分匹配字元才能被跳過。那麼那個」內在模式「是什麼呢?
為了理解這種無法簡單跳過的情況,我們有了」字首「和」字尾「等概念。同時也發現,那些部分匹配的情況,我們不需要考慮主串,直接可以用模式串來分析。
這些」重複出現的字首「就是我們要尋找的」內在模式「。因此我們要分析模式串的每乙個字首,同時他們的長度和陣列下標一一對應,那麼我們只需要分析這些」重複出現的字首「的長度即可,於是我們定義部分匹配值,為能在字首裡找到的最長的」內在模式「的長度。
可上圖說的是跳轉?那是因為二者是等價的概念,想不明白就暫停仔細想想(下標、長度)。
於是我們目前優化暴力匹配演算法的方案有了,」事前分析「模式串然後製表(next陣列),根據這個表跳轉模式串指標的位置,保持主串指標不復位。(從而跳過那些無限復位考慮的子串,又不會錯過潛在匹配成功的子串)。
可是,如何計算next陣列呢?
我們可以人工推算出部分匹配值表(考慮每乙個字首的字首集合和字尾集合,找到二者交集的最長元素,該長度就是這個字首的部分匹配值),然後根據等價關係換算到next陣列。
但是,如果編碼計算呢?畢竟程式沒有提供集合運算(或者為了高效,我們也不應該採取集合運算)。沒辦法了,只能把每種情況,在」記憶體裡看起來是什麼樣子的「畫一畫。看有沒有思路吧。
所以我們可以從最小字首開始,不斷利用並構造next陣列!用c++試試看。
#include
最後,還可以對next陣列進行優化,因為還存在一種情況,跳轉指向的字元與當前字元一樣,那麼匹配一定會失敗從而繼續發生next跳轉(回溯),不如在構造next陣列時就把這種情況考慮進去,從而完成優化。 模式匹配 KMP演算法
字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...
模式匹配KMP演算法
前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...
KMP模式匹配演算法
首先,這是由knuth morris和prattle三人設計的線性時間字串匹配演算法。這裡就不仔細的講解,網上有更好的講解,在這推薦幾個自己當時學習的kmp所看到的較好理解的 這裡附上自己所學的 includeusing namespace std s 是主串 p 是模式串 int next 100...