經典演算法 KMP,深入講解next陣列的求解

2021-08-21 21:18:37 字數 2789 閱讀 2375

本部分內容**:

字串匹配是計算機的基本任務之一。

舉例來說,有乙個字串」bbc abcdab abcdabcdabde「,我想知道,裡面是否包含另乙個字串」abcdabd「?

許多演算法可以完成這個任務,knuth-morris-pratt演算法(簡稱kmp)是最常用的之一。它以三個發明者命名,起頭的那個k就是著名科學家donald knuth。

這種演算法不太容易理解,網上有很多解釋,但讀起來都很費勁。直到讀到jake boxer的文章,我才真正理解這種演算法。下面,我用自己的語言,試圖寫一篇比較好懂的kmp演算法解釋。

1.

首先,字串」bbc abcdab abcdabcdabde「的第乙個字元與搜尋詞」abcdabd「的第乙個字元,進行比較。因為b與a不匹配,所以搜尋詞後移一位。

2.

因為ba不匹配,搜尋詞再往後移。

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開始,...