模式匹配的kmp演算法詳解
這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。
注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來,其實理解的關鍵就在這裡,一般的匹配演算法:
int index(string s,string t,int pos)//參考《資料結構》中的程式
else//**************(1)
}if(j>t.length) return i-t.length;//匹配成功
else return 0;}
匹配的過程非常清晰,關鍵是當『失配』的時候程式是如何處理的?回溯,沒錯,注意到(1)句,為什麼要回溯,看下面的例子:
s:aaaaabababcaaa t:ababc
aaaaabababcaaa
ababc.(.表示前乙個已經失配)
回溯的結果就是
aaaaabababcaaa
a.(babc)
如果不回溯就是
aaaaabababcaaa
aba.bc
這樣就漏了乙個可能匹配成功的情況
aaaaabababcaaa
ababc
為什麼會發生這樣的情況?這是由t串本身的性質決定的,是因為t串本身有前後'部分匹配'的性質。如果t為abcdef這樣的,大沒有回溯的必要。
改進的地方也就是這裡,我們從t串本身出發,事先就找準了t自身前後部分匹配的位置,那就可以改進演算法。
如果不用回溯,那t串下乙個位置從**開始呢?
還是上面那個例子,t為ababc,如果c失配,那就可以往前移到aba最後乙個a的位置,像這樣:
...ababd...
ababc
->ababc
這樣i不用回溯,j跳到前2個位置,繼續匹配的過程,這就是kmp演算法所在。這個當t[j]失配後,j應該往前跳的值就是j的next值,它是由t串本身固有決定的,與s串無關。
《資料結構》上給了next值的定義:
0 如果j=1
next[j]= //注意到這裡的j==0,和++j的作用就知道為什麼規定next[1]=0的好處了
else j=next[j];//i不變(不回溯),j跳動
}if(j>t.length) return i-t.length;//匹配成功
else return 0;}
ok,是不是非常簡單?還有更簡單的,求next值,這也是整個演算法成功的關鍵,從next值的定義來求太恐怖了,怎麼求?前面說過了,next值 表達的就是t串的自身部分匹配的性質,那麼,我只要將t串和t串自身來一次匹配就可以求出來了,這裡的匹配過程不是從頭乙個乙個匹配,而是從t[1]和t [2]開始匹配,給出演算法如下:
void get_next(string t,int &next)
else j=next[j];}}
看這個函式是不是非常像kmp匹配的函式,沒錯,它就是這麼幹的!注意到(2)語句邏輯覆蓋的時候是t[i]==t[j]以及i前面的、j前面的都 匹配的情況下,於是先自增,然後記下來next[i]=j,這樣每當i有自增就會求得乙個next[i],而j一定會小於等於i,於是對於已經求出來的 next,可以繼續求後面的next,而next[1]=0是已知,所以整個就這樣遞推的求出來了,方法非常巧妙。
這樣的改進已經是很不錯了,但演算法還可以改進,注意到下面的匹配情況:
...aaac...
aaaa.
t串中的'a'和s串中的'c'失配,而'a'的next值指的還是'a',那同樣的比較還 是會失配,而這樣的比較是多餘的,如果我事先知道,當t[i]==t[j],那next[i]就設為next[j],在求next值的時候就已經比較了, 這樣就可以去掉這樣的多餘的比較。於是稍加改進得到:
void get_nextval(string t,int &next)
else j=next[j];}}
匹配演算法不變。
到此就完全弄清楚了,以前老覺得kmp演算法好神秘,真不是人想出來的,其實不然,它只不過是對原有的演算法進行了改進。可見基礎的經典的東西還是很重要,你有本事『廢』了經典,就創造了進步。
模式匹配 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...