from
這種由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演算法
10170330 容易 include include include define error 0 define maxsize 100 using namespace std 串的暴力匹配演算法 brute force 該函式的作用是返回子z串t在s中第position個字元之後的位置 時間複雜...
演算法 kmp匹配演算法
執行結果 心得收穫 完整 計算next陣列 next陣列的目標是求得從開始到當前位置的字串相同最大前字尾長度為多少 該值的作用是在當前位置的字元匹配失敗時,匹配字串應該從那裡開始繼續匹配,而不用回到開頭 時間複雜的 o m void calnextarray const string str,int...
c kmp演算法字元匹配 KMP模式匹配演算法
我從對暴力匹配演算法的優化角度出發,理解和構造出kmp演算法。模式匹配問題中,有主串,子串,模式串,字首,字尾,部分匹配值等等概念。教材往往 反著來 先有解決方案和概念,再強行說 啊,就是這樣子的 但我們都應該清楚,概念是輔助思考,輔助解決遇到的問題的。假設我們已經弄懂了暴力匹配解決模式匹配的方法,...