1. 程式人生 > >字符串匹配的KMP算法

字符串匹配的KMP算法

ews 時間復雜度 會有 bcd cda www http 前綴和 組合

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

  舉例來說,有一個字符串"BBC ABCDAB ABCDABCDABDE"。我想知道。裏面是否包括還有一個字符串"ABCDABD"?

技術分享

  很多算法能夠完畢這個任務,Knuth-Morris-Pratt算法(簡稱KMP)是最經常使用的之中的一個。它以三個發明者命名。起頭的那個K就是著名科學家Donald Knuth。

技術分享

  這樣的算法不太easy理解。網上有非常多

q=Knuth-Morris-Pratt+algorithm" target="_blank">解釋。但讀起來都非常費勁。直到讀到Jake Boxer的文章。我才真正理解這樣的算法。

以下,我用自己的語言,試圖寫一篇比較好懂的KMP算法解釋。

  1.

技術分享

  首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一個字符與搜索詞"ABCDABD"的第一個字符。進行比較。由於B與A不匹配。所以搜索詞後移一位。

  2.

技術分享

  由於B與A不匹配,搜索詞再往後移。

  3.

技術分享

  就這樣,直到字符串有一個字符。與搜索詞的第一個字符同樣為止。

  4.

技術分享

  接著比較字符串和搜索詞的下一個字符。還是同樣。

  5.

技術分享

  直到字符串有一個字符。與搜索詞相應的字符不同樣為止。

  6.

技術分享

  這時,最自然的反應是,將搜索詞整個後移一位,再從頭逐個比較。這樣做盡管可行,可是效率非常差,由於你要把"搜索位置"移到已經比較過的位置,重比一遍。

  7.

技術分享

  一個基本事實是,當空格與D不匹配時,你事實上知道前面六個字符是"ABCDAB"。KMP算法的想法是。設法利用這個已知信息。不要把"搜索位置"移回已經比較過的位置,繼續把它向後移。這樣就提高了效率。

  8.

技術分享

  怎麽做到這一點呢?能夠針對搜索詞,算出一張《部分匹配表》(Partial Match Table)。這張表是怎樣產生的,後面再介紹。這裏僅僅要會用就能夠了。

  9.

技術分享

  已知空格與D不匹配時,前面六個字符"ABCDAB"是匹配的。

查表可知。最後一個匹配字符B相應的"部分匹配值"為2。因此依照以下的公式算出向後移動的位數:

  移動位數 = 已匹配的字符數 - 相應的部分匹配值

  由於 6 - 2 等於4,所以將搜索詞向後移動4位。

  10.

技術分享

  由於空格與C不匹配,搜索詞還要繼續往後移。這時,已匹配的字符數為2("AB"),相應的"部分匹配值"為0。所以,移動位數 = 2 - 0,結果為 2。於是將搜索詞向後移2位。

  11.

技術分享

  由於空格與A不匹配,繼續後移一位。

  12.

技術分享

  逐位比較,直到發現C與D不匹配。於是。移動位數 = 6 - 2,繼續將搜索詞向後移動4位。

  13.

技術分享

  逐位比較,直到搜索詞的最後一位,發現全然匹配,於是搜索完畢。

假設還要繼續搜索(即找出所有匹配)。移動位數 = 7 - 0,再將搜索詞向後移動7位,這裏就不再反復了。

  14.

技術分享

  以下介紹《部分匹配表》是怎樣產生的。

  首先。要了解兩個概念:"前綴"和"後綴"。 "前綴"指除了最後一個字符以外,一個字符串的所有頭部組合;"後綴"指除了第一個字符以外。一個字符串的所有尾部組合。

  15.

技術分享

  "部分匹配值"就是"前綴"和"後綴"的最長的共同擁有元素的長度。以"ABCDABD"為例,

  - "A"的前綴和後綴都為空集,共同擁有元素的長度為0;

  - "AB"的前綴為[A]。後綴為[B],共同擁有元素的長度為0。

  - "ABC"的前綴為[A, AB]。後綴為[BC, C]。共同擁有元素的長度0;

  - "ABCD"的前綴為[A, AB, ABC],後綴為[BCD, CD, D],共同擁有元素的長度為0;

  - "ABCDA"的前綴為[A, AB, ABC, ABCD]。後綴為[BCDA, CDA, DA, A],共同擁有元素為"A",長度為1;

  - "ABCDAB"的前綴為[A, AB, ABC, ABCD, ABCDA],後綴為[BCDAB, CDAB, DAB, AB, B],共同擁有元素為"AB",長度為2。

  - "ABCDABD"的前綴為[A, AB, ABC, ABCD, ABCDA, ABCDAB]。後綴為[BCDABD, CDABD, DABD, ABD, BD, D],共同擁有元素的長度為0。

  16.

技術分享

  "部分匹配"的實質是,有時候。字符串頭部和尾部會有反復。

比方,"ABCDAB"之中有兩個"AB"。那麽它的"部分匹配值"就是2("AB"的長度)。

搜索詞移動的時候。第一個"AB"向後移動4位(字符串長度-部分匹配值),就能夠來到第二個"AB"的位置。


KMP的算法流程:

  • 如果如今文本串S匹配到 i 位置。模式串P匹配到 j 位置
    • 假設j = -1,或者當前字符匹配成功(即S[i] == P[j]),都令i++,j++,繼續匹配下一個字符。
    • 假設j != -1,且當前字符匹配失敗(即S[i] != P[j])。則令 i 不變。j = next[j]。此舉意味著失配時,模式串P相對於文本串S向右移動了j - next [j] 位。

我們發現假設某個字符匹配成功。模式串首字符的位置保持不動,不過i++、j++;假設匹配失配。i 不變(即 i 不回溯),模式串會跳過匹配過的next [j]個字符。整個算法最壞的情況是,當模式串首字符位於i - j的位置時才匹配成功,算法結束。
所以。假設文本串的長度為n。模式串的長度為m。那麽匹配過程的時間復雜度為O(n),算上計算next的O(m)時間。KMP的總體時間復雜度為O(m + n)


很多其它了解能夠查看July解說:http://blog.csdn.net/v_july_v/article/details/7041827

字符串匹配的KMP算法