1. 程式人生 > >字串匹配演算法——KMP演算法簡單解釋

字串匹配演算法——KMP演算法簡單解釋

一、字串匹配演算法KMP

KMP演算法是一種改進的字串匹配演算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現,因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP演算法)。KMP演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函式,函式本身包含了模式串的區域性匹配資訊。時間複雜度O(m+n)。

二、KMP演算法圖解

這種演算法在網上看了很多解釋,大部分都比較晦澀複雜,直到看到了一篇文章才是真的簡單易懂,包教包會,這裡就按照自己的理解寫一篇文章。
我們用一個例子來看,在字串“WWE QWERQW QWERQWERQWRT”中查詢是否含有另一個字串“QWERQWR”。通常做法是將兩個字串進行一個個比對,當發現一個字元一致時,進行第二個字元的比對,如果發現不一致,再退回去從首字元的下一個開始進行新一輪比對,空口說不太好理解,下面我們結合圖來看KMP演算法是如何利用普通匹配失敗的資訊加快效率的。
1.
這裡寫圖片描述


我們先將兩個字串的第一個字元進行比對,因為W和Q不匹配,因此跳到下個字元開始匹配。
2.
這裡寫圖片描述
第二位的字元也不匹配,繼續後移
3.
這裡寫圖片描述
依次比對,直到發現第一個字元相同的情況
4.
這裡寫圖片描述
然後接著從第二個字元開始對應比對,直到有一個字元與搜尋詞對應不相同為止
5.
這時,樸素的對比方法是將搜尋詞後移一位,再從頭逐個比對,例如:
這裡寫圖片描述
這種方法當然是可行的,但是就體現不出演算法的高效了。
6.
而在KMP演算法中,當我們知道空格和”R”不匹配時,我就相當於知道了它的前面六個字元是”QWERQW”,KMP演算法中需要設法利用這個已知了的資訊,讓搜尋位置後移提供效率。這裡我們用到了一張表,叫做“部分匹配表”,後面我們會再說如何計算出這張表,這裡我們只說如何使用。

搜尋詞 Q W E R Q W R
部分匹配值 0 0 0 0 1 2 0

7.
這裡寫圖片描述
當我們知道空格和“R”不匹配時,前面六個字元是匹配的。查表可知,最後一個匹配字元W對應的部分匹配值是2,按照公式:
移動位數 = 已匹配的字元數 - 對應的部分匹配值
得到6 - 2 = 4,因此將搜尋詞向後移動4位。
8.
這裡寫圖片描述
移動四位後比對,發現第三位不匹配,此時依據公式移動位數 = 已匹配字元數(2) - 對應的部分匹配值(0) = 2,因此繼續向後移動兩位
9.
這裡寫圖片描述
第一位不匹配,向後移動一位
這裡寫圖片描述
此時又是和第步驟7一樣,繼續移動6 - 2 = 4位
10.
這裡寫圖片描述


此時發現全部七位匹配相同,所以第一個搜尋完成了,如果還需要繼續搜尋(查詢所有匹配欄位),就繼續向後移動 = 7 - 0 位,下面就不在贅述了。

三、部分匹配表

接下來說一下部分匹配表是如何生成的。首先,要了解兩個概念:”字首”和”字尾”。 “字首”指除了最後一個字元以外,一個字串的全部頭部組合;”字尾”指除了第一個字元以外,一個字串的全部尾部組合。
例如:單詞level的字首有{l,le,lev,leve}四個,字尾有{evel,vel,el,l}四個,然後字首和字尾集合取交集,得到{l},只有一個元素,長度為1,因此level的部分匹配值就是1。

搜尋詞 Q W E R Q W R
部分匹配值 0 0 0 0 1 2 0

再回來看上面的字串例子:
“Q”的字首和字尾都為空集,共有元素的長度為0;
“QW”的字首為[Q],字尾為[W],共有元素的長度為0;
“QWE”的字首為[Q, QW],字尾為[WE, E],共有元素的長度0;
“QWER”的字首為[Q, QW, QWE],字尾為[WER, ER, R],共有元素的長度為0;
“QWERQ”的字首為[Q, QW, QWE, QWER],字尾為[WERQ, ERQ, RQ, Q],共有元素為”Q”,長度為1;
“QWERQW”的字首為[Q, QW, QWE, QWER, QWERQ],字尾為[WERQW, ERQW, RQW, QW, W],共有元素為”QW”,長度為2;
“QWERQWR”的字首為[Q, QW, QWE, QWER, QWERQ, QWERQW],字尾為[WERQWR, ERQWR, RQWR, QWR, WR, R],共有元素的長度為0。

“部分匹配”的實質是,有時候,字串頭部和尾部會有重複。比如,”QWERQW”之中有兩個”QW”,那麼它的”部分匹配值”就是2(”QW”的長度)。搜尋詞移動的時候,第一個”QW”向後移動4位(字串長度-部分匹配值),就可以來到第二個”QW”的位置。

總之,KMP演算法還是很巧妙的利用了已經得到的資訊,這也正是演算法巧妙的地方,積少成多,在大量的字元創匹配中帶來的效率提升是好幾倍的。KMP演算法的程式碼實現在下一篇中給出,謝謝

相關推薦

用於字串匹配KMP演算法

KMP演算法的理解分為兩個部分: 1.如何利用next陣列(最大前後綴長度)匹配字元。 藉助next陣列,原字串的i可以不回移,如果當前字元失配則前模式串的j即可。因為雖然當前s[i]和t[j]失配,但是我們知道j之前的字元是匹配的,只要確定t[0]~t[j-1]的最長前後綴,就可以通過移動

字串匹配KMP演算法

1.kmp演算法的原理: 字串匹配是計算機的基本任務之一。 舉例來說,有一個字串"BBC ABCDAB ABCDABCDABDE",我想知道,裡面是否包含另一個字串"ABCDABD"? 許多演算法可以完成這個任務,Knuth-Morris-Pratt演算法(

字串匹配KMP演算法--字首和字尾的詳解

字串匹配是計算機的基本任務之一。 舉例來說,有一個字串"BBC ABCDAB ABCDABCDABDE",我想知道,裡面是否包含另一個字串"ABCDABD"? 許多演算法可以完成這個任務,Knuth-Morris-Pratt演算法(簡稱KMP)是最常用的之一。它以三個發明者命名,起頭的那個K就是著

資料結構-字串匹配KMP演算法、BF演算法、BM演算法

本程式碼中用了KMP演算法、BF演算法、BM演算法三種演算法進行字串匹配。文字串儲存在了test.txt中,模式串需自行輸入。程式碼如下:#include"stdio.h" #include"stdio.h" #include"stdlib.h" #include"conio

字串匹配KMP演算法---計算失配函式

關於理解計算失配函式的一點小心得。 首先,感謝Jake Boxer的文章給我的幫助。 在jake的文章裡面,說的,字首和字尾是理解的關鍵。請先閱讀以下jake的文章(不然可能不好理解)。 正題:假設字串 P 的長度是 m。我們給定 P 的失配函式為 failure[m]

字串匹配問題 kmp演算法C語言實現

{    int n,k;    int next[MAX]=...{0} ;    int lA=0,la =0 ;    char A[MAX],a[MAX] ;    scanf("%s %s",A,a) ;        lA = strlen(A);    la = strlen(a);    fo

字串匹配演算法——KMP演算法簡單解釋

一、字串匹配演算法KMP KMP演算法是一種改進的字串匹配演算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現,因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP演算法)。KMP演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串

字串匹配演算法——KMP演算法

KMP演算法是一種改進的字串匹配演算法。KMP演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函式,函式本身包含了模式串的區域性匹配資訊。   下面從一個例子來了解KMP演算法:字串"BBC ABCDAB ABCD

高效面試之字串匹配KMP,AC演算法

3.AC 多模匹配演算法  看下面這個例子:給定5個單詞:say she shr he her,然後給定一個字串yasherhs。問一共有多少單詞在這個字串中出現過。 三步:構建trik樹,給trik樹新增失敗路徑,建立AC自動機,根據AC自動機搜尋文字 1.構建trik樹  1constint ki

字串匹配的Sunday演算法--效能上超過KMP和BM演算法

第一次聽到Sunday演算法,是大餅餅說的。在他圖文並茂的解釋中,我發現這個演算法果然是一個又容易理解,效率又強過kmp和BM的演算法。 Sunday的移動次數更少! 於是試著寫了一個,果真是好東東,分享一下。 轉一些概念先: Sunday演算法是Daniel M.Sun

字串的模式匹配--BF演算法&KMP演算法

BF演算法是基於主串指標回溯,重新與子串進行逐字元進行比較,主串為S什麼要進行回溯呢,原因在於模式P中存在相同的字元或者說由字元(串)存在重複(模式的部分匹配性質),設想如果模式P中字元各不相同,主串就S的指標就根本不需要回溯;然而,我們可以發現在主串S與模式發

字串匹配的RabinKarp演算法的c語言實現

</pre><pre name="code" class="cpp">#include<string.h> int check( char *s1,char *s2,int n ); int main() { char s1[10000],s2[1000000]

演算法:模式匹配KMP演算法

前言:   昨天看到《演算法導論》裡的第32章:字串匹配,說到一個關於字串匹配的很好的演算法——KMP。關於KMP的記憶體含意以及KMP的來源,不是本文講述的範疇,請感興趣的讀者自行查閱相關資料。  

Java字串匹配相似度演算法

/** * 採用動態規劃的方法(字串匹配相似度) * @param source 源 * @param target 要匹配的字串 * @return */ public static int EditDistance(String

模式串匹配KMP演算法詳解

KMP演算法,是由Knuth,Morris,Pratt共同提出的模式匹配演算法,其對於任何模式和目標序列,都可以線上性時間內完成匹配查詢,而不會發生退化,是一個非常優秀的模式匹配演算法。但是相較於其他模式匹配演算法,該演算法晦澀難懂,第一次接觸該演算法的讀者往往會看得一頭

字串匹配自動機的演算法原理

上一節,我們知道,如何構造一個有限狀態機,用於字串匹配,我們只給出了怎麼做,這一節,我們詳細說明一下,為什麼要這麼做,我們要從數學上驗證上一節我們給出的演算法邏輯是經得起考驗的。 如上圖所示,有限狀態自動機有以下幾個特點: 1. 它由一系列的狀態節點組成

【模式匹配KMP演算法的來龍去脈

1. 引言 字串匹配是極為常見的一種模式匹配。簡單地說,就是判斷主串\(T\)中是否出現該模式串\(P\),即\(P\)為\(T\)的子串。特別地,定義主串為\(T[0 \dots n-1]\),模式串為\(P[0 \dots p-1]\),則主串與模式串的長度各為\(n\)與\(p\)。 暴力匹配 暴力匹配

字串匹配之RK演算法——學習筆記

RK演算法是Rabin-Karp演算法的簡稱,是經典的字串匹配演算法,在《演算法導論》上是有介紹的,有興趣的同學可以去看看。 RK演算法的複雜度可以說是比上不足比下有餘,比一般的匹配演算法要好,但是又比不上KMP,Sunday等演算法。演算法表現跟快排比較相似,演算法平均複

字串匹配之---BF演算法(暴力破解法)

        寫完第一篇字串匹配文章,發現竟然沒有介紹啥是字串匹配演算法,啥是KMP,直接就開講KMP的next陣列有點唐突。而在我打算寫第二篇的時候發現,我們為什麼要有KMP演算法,它到底比普通的演算法好在哪裡?回過頭來想想應該把普通的暴力法也寫寫,這樣才能明白它們的好

C/C++/Java程式碼 樸素的(暴力法)模式匹配演算法 KMP演算法 資料結構

樸素的模式匹配(暴力法)演算法 演算法思想: 從目標串的的第一個字元起與模式串的第一個字元比較,若相等,則繼續對字元進行後續的比較,否則目標串從第二個字元起與模式串的第一個字元重新比較,直至模式串中的每個字元依次和目標串中的一個連續的字元序列相等為止,此時稱為匹配