一、簡介
KMP算法,首先與BF算法做比較…….(此處略去簡介200字,至於哪200字,網上隨便找一篇講KMP算法的基本上都會先講樸素算法);
二、題外話
記得大二的時候,DS課程設計就是實現KMP算法,當時也沒弄太清楚(或者弄清楚了也忘記了),就知道在網上搜到了代碼,然後就好用!然而這幾天抱着深入學習的態度,反而有點暈,可能年紀大了吧!在網上找到很多資料把我看的直接拔電源了都!我想說的是,根據自己這兩天在網上的搜索可知,很多關於KMP算法的介紹的文章,篇幅都比較長,沒有心情看下去,而且感覺不能突出重點,我只想問,有那麼複雜嗎?也許是優化版很多吧。那麼,接下來,我們就用圖標的方式,來分析一下,這個算法到底有多複雜。
三、主題
主題沒有代碼,只有圖表。下面,我們就以
爲例,我們來學習這個算法的思想。
1. 關於Next數組
什麼是Next數組,Next數組時幹嘛的呢?不知道?那就自己搜搜去。
這個算法的關鍵,就是Next數組的構造與使用,使用當然就很簡單,主要的是來看看構造。
我們將KMP原始算法 與 KMP改進算法對比着來看。
原始算法:
1. Next[0] = -1:因爲由失配發生時,模式串跳轉的位置爲:右移動j - Next[j]長度.
若在首位置失配,只能右移一位,類似樸素算法,所以要右移一位,又要將這種情況套入:j - Next[j] 因此,只能爲-1。
2. Next[j] 的值爲:
若存在一個k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 個字符與Next[j-k],Next[j-k+1]…Next[j-1]相等,則 Next[j] = k;
若不存在一個k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 個字符 與 Next[j-k],Next[j-k+1]…Next[j-1]相等,則 Next[j] = 0;
改進算法:
1. 1.Next[0] = -1;同上
2. .Next[j] 的值爲:
若存在一個k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 個字符 與 Next[j-k],Next[j-k+1]…Next[j-1]相等,並且 Next[k] != Next[j] 則 Next[j] = k;否則若Next[k] == Next[j] 則 Next[j] = -1;
若不存在一個k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 個字符 與 Next[j-k],Next[j-k+1]…Next[j-1]相等,並且 Next[0] == Next[j] 則 Next[j] = -1;否則若Next[0] != Next[j] 則 Next[j] = 0;
根據以上原則,我們來計算一下我們的模式串的Next函數
//根據以上的圖我們知道Next數組的計算了,至於代碼,我就只貼一下改進算法的好了
void GetNextval(const SWORD *pswPattern, SDWORD *psdNext, SDWORD sdLength )
{
// 求模式串pswPattern的next函數值並存入數組 next。
SDWORD j = 0, k = -1;
psdNext[0] = -1;
while ( j < sdLength ) {
if ( k == -1 || pswPattern[j] == pswPattern[k] ) {
++j; ++k;
if ( pswPattern[j] != pswPattern[k] ) {
psdNext[j] = k;
}
else {
psdNext[j] = psdNext[k];
}
}
else {
k = psdNext[k];
}
}
}
OK,Next數組我們求出來了,我們再列個表格來展示一下兩種算法的匹配過程吧
原始算法
改進算法:
四、結語
Sunday算法是另外一種匹配算法,據說比KMP要高效,還沒學習,等以後學習了再加上吧。《算法導論》上關於KMP的內容基本上都是一些理論證明,如果數學比較好的童鞋可以看看,如果只是爲了應用,那麼,網上隨便找到的完整代碼都是可以用的了。
可能我的表述有些簡單,或者哪裏表述的不對,還請諸位指正,因爲這兩天有點懵圈了,難免有疏漏或者理解錯誤之處,敬請原諒。