這種由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演算法詳解
kmp 模式匹配演算法 include include using namespace std 計算模式串的next陣列 模式串既做主串,又做模式串,進行匹配 時間複雜度為o m m為模式串的長度 void countnext char strpattern,int len,int next els...
模式匹配的KMP演算法詳解
from 模式匹配的kmp演算法詳解 這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來...
模式匹配演算法(KMP演算法詳解)
從主串s goodgoogle 中找到t google 這個子串的位置 public static intindex string s,string t else if j t.length else 思路 利用已經部分匹配這個有效資訊,保持i指標不回溯,通過修改j指標,讓模式串盡量地移動到有效的位...