本部分內容**:
字串匹配是計算機的基本任務之一。
舉例來說,有乙個字串」bbc abcdab abcdabcdabde
「,我想知道,裡面是否包含另乙個字串」abcdabd
「?
許多演算法可以完成這個任務,knuth-morris-pratt演算法(簡稱kmp)是最常用的之一。它以三個發明者命名,起頭的那個k就是著名科學家donald knuth。
這種演算法不太容易理解,網上有很多解釋,但讀起來都很費勁。直到讀到jake boxer的文章,我才真正理解這種演算法。下面,我用自己的語言,試圖寫一篇比較好懂的kmp演算法解釋。
1.
首先,字串」bbc abcdab abcdabcdabde
「的第乙個字元與搜尋詞」abcdabd
「的第乙個字元,進行比較。因為b與a不匹配,所以搜尋詞後移一位。
2.
因為b
與a
不匹配,搜尋詞再往後移。
3.
就這樣,直到字串有乙個字元,與搜尋詞的第乙個字元相同為止。
4.
接著比較字串和搜尋詞的下乙個字元,還是相同。
5.
直到字串有乙個字元,與搜尋詞對應的字元不相同為止。
6.
這時,最自然的反應是,將搜尋詞整個後移一位,再從頭逐個比較。這樣做雖然可行,但是效率很差,因為你要把」搜尋位置」移到已經比較過的位置,重比一遍。
7.
8.
怎麼做到這一點呢?可以針對搜尋詞,算出一張《部分匹配表》(partial match table)。這張表是如何產生的,後面再介紹,這裡只要會用就可以了。
9.
已知空格與d不匹配時,前面六個字元」abcdab」是匹配的。查表可知,最後乙個匹配字元b對應的」部分匹配值」為2,因此按照下面的公式算出向後移動的位數:
移動位數 = 已匹配的字元數 - 對應的部分匹配值
因為6 - 2
等於4
,所以將搜尋詞向後移動4位。
10.
11.
因為空格與a不匹配,繼續後移一位。
12.
逐位比較,直到發現c與d不匹配。於是,移動位數 =6 - 2
,繼續將搜尋詞向後移動4位。
13.
14.
首先,要了解兩個概念:」字首」和」字尾」。 「字首」指除了最後乙個字元以外,乙個字串的全部頭部組合;」字尾」指除了第乙個字元以外,乙個字串的全部尾部組合。
1.
「部分匹配值」就是」字首」和」字尾」的最長的共有元素的長度。以」abcdabd
「為例,
2.
「部分匹配」的實質是,有時候,字串頭部和尾部會有重複。比如,」abcdab
「之中有兩個」ab」,那麼它的」部分匹配值」就是2(」ab」的長度)。搜尋詞移動的時候,第乙個」ab」向後移動4位(字串長度-部分匹配值),就可以來到第二個」ab」的位置。
void makenext(const
char p,int next)
next[q] = k;}}
現在我著重講解一下while迴圈所做的工作:
已知前一步計算時最大相同的前字尾長度為k(k>0),即p[0]···p[k-1];
此時比較第k項p[k]與p[q],如圖1所示
如果p[k]等於p[q],那麼很簡單跳出while迴圈;
關鍵!關鍵有木有!關鍵如果不等呢???那麼我們應該利用已經得到的next[0]···next[k-1]來求p[0]···p[k-1]這個子串中最大相同前字尾,可能有同學要問了——為什麼要求p[0]···p[k-1]的最大相同前字尾呢???是啊!為什麼呢? 原因在於p[k]已經和p[q]失配了,而且p[q-k] ··· p[q-1]又與p[0] ···p[k-1]相同,看來p[0]···p[k-1]這麼長的子串是用不了了,那麼我要找個同樣也是p[0]打頭、p[k-1]結尾的子串即p[0]···pj-1,看看它的下一項p[j]是否能和p[q]匹配。如圖2所示
#include
#include
void makenext(const
char p,int next)
next[q] = k;
}}int kmp(const
char t,const
char p,int next)
if (q == m)
}
}int main()
; char t = "ababxbababcadfdsss";
char p = "abcdabd";
printf("%s\n",t);
printf("%s\n",p );
// makenext(p,next);
kmp(t,p,next);
for (i = 0; i < strlen(p); ++i)
printf("\n");
return
0;}
經典演算法 KMP,深入講解next陣列的求解
原部落格位址 前言 之前對kmp演算法雖然了解它的原理,即求出p0 pi的最大相同前字尾長度k 但是問題在於如何求出這個最大前字尾長度呢?我覺得網上很多帖子都說的不是很清楚,總感覺沒有把那層紙戳破,後來翻看演算法導論,32章 字串匹配雖然講到 了對前1.kmp演算法的原理 本部分內容 字串匹配是計算...
kmp演算法next例題 KMP演算法next陣列求解
kmp演算法與bf演算法的比較 bf演算法的想法十分樸素,即先將子串t的第一位與主串s的第一位對齊開始匹配,當不能匹配時將子串整體往後移一位,然後重新匹配,以此類推直至排出結果 如當遇到下圖所示情況時,需將子串整體後移一位,將i,j分別回溯到主串第2位和子串第一位。kmp演算法 對bf進行思考後,我...
KMP演算法經典講解
kmp演算法的思想都是一樣的,看了很多講解,基本上都只是在next陣列的表示上是有區別的,我覺得乙個很6的大神,講的很好 這位大神的next i 表示的是如果模板串p的第i位與母串s匹配失敗,則從模板串的哪個位置開始進行下一次比較。母串s和模板串p都是從0開始到len 1,next陣列也是從0開始,...