KMP字串匹配演算法

2021-09-01 01:31:10 字數 2849 閱讀 8270

kmp

演算法,knuth-morris-pratt algorithm

,一種由knuth(d.e.knuth)、morris(j.h.morris)和pratt(v.r.pratt)三人提出的一種快速模式匹配演算法。

kmp樸素演算法

原理:子串pattern依次與目標串target中的字元比較,如果相等,繼續比較下乙個字元;如果不等,pattern右移一位,重新開始比較,直至匹配正確或超出target。

示例:子串pattern=,目標串target=,比較過程如下圖:

特點:思路簡單、**直觀;但效率低、有回溯、不夠簡潔、時間複雜度高

// 在target中查詢子串pattern的起始位置,pos初始為0 int index(char *target, char *pattern, int pos) int k = pos, j = 0; while(k小結:在最壞的情況下,每次比較都在最後乙個字元出現不等(如aaaaaaaaaaaaab和ab)

假設pattern長度為m,target長度為n,則每趟最多比較m次,最多迴圈比較(n-m)趟,總比較次數為m*(n-m),即時間複雜度為o(m*n)

kmp演算法的演變

我們由上面kmp樸素演算法的例子來引出乙個問題。

為了便於問題分析,令p(pattern),t(target),字元陣列下標從0開始。通過仔細分析,發現p(pattern)前4個字元是匹配的,只有最後乙個字元p[4]不匹配!

如果p右移1位,p前兩字元aa又將與t(target)的ab不匹配

如果p右移2位,p第乙個字元a就與t的b不匹配

如果p右移3位,p前兩字元aa又將於t的ab不匹配(同右移1位的情況)

如果p右移4位,p第乙個字元a就與t的b不匹配(同右移2位的情況)

如果p右移5位,即p跨過已經與t比較過的五位了,省去了右移1、2、3、4位的步驟

為什麼是5位呢?我們再深入分析,轉換思考問題的側重點,發現5位字元正好是p(pattern)子串的長度,是不是p子串本身就蘊含了模式匹配的奧秘?

答案是肯定的!

p: aabaa(x) 注意:最後乙個字元不匹配,即a(x)

上圖直觀給出,p要麼右移3位,要麼右移5位,才有可能與t(target)出現匹配。

我們探索p本身的規律,發現p(aabaa)移位的大小,與其自身的首尾覆蓋特性有關,即aa—b—aa(移3位跳過b字元,移5位跳過自身,從頭開始比較)

於是我們引出了另外乙個問題——覆蓋函式

什麼是覆蓋函式呢?我們直接給出定義:

對於序列

找出這樣乙個k,使其滿足

並且要求k盡可能的大!(原因後面再講)

求p自身最大的k值,對於p(pattern)的前j序列字元(從下標0計起),有兩種可能:

1、 pattern[j] ==pattern[preoverlay+1]時,overlay(j) = preoverlay + 1 = overlay(j-1) + 1

2、 pattern[j] !=pattern[preoverlay+1]時,overlay(j)需要在前preoverlay中找;使preoverlay = overlay[preoverlay],重複2過程

// 求pattern覆蓋 void overlay_pattern(const char *pattern) if (pattern[i] == pattern[preoverlay+1])else } for(i=0; i例如p: aabaa 其overlay依次為:-1、0、-1、0、1

-1表示沒有覆蓋,0表示有乙個覆蓋,1表示有兩個覆蓋,從-1開始計起

再如p:

abaabcabab 其overlay依次為:-1、-1、0、0、1、-1、0、1、2、1

kmp演算法

kmp演算法,是由kmp樸素演算法演變而來的,主要分為兩步:

第一步,當字串比較出現不等時,確定下一趟比較前,應該將子串pattern右移多少個字元(預處理)

第二步,子串pattern右移後,應該從哪個字元開始和目標串target中剛才比較時不等的那個字元繼續開始比較(查詢)

下面給出完整的kmp演算法:

#include #include #include // 預處理子串 void kmp_prepare(char *target, char *pattern, int *overlay) if(pattern[i] == pattern[preoverlay+1])else } for(i=0; i

測試示例:

pattern: aabaa

target: aababaacaabaa

執行結果:

總結:

第一步,其實就是kmp樸素演算法對模式匹配子串pattern的預處理過程,上面已經給出了演算法公式和**示例

第二步,本質上就是kmp樸素演算法,不同的僅僅是pattern右移的位數大小由其預處理過程決定

kmp演算法不太容易理解,但其簡潔、高效,時間複雜度為o(m+n)

其中,o(m)是pattern子串預處理的時間複雜度,o(n)是target目標串查詢的時間複雜度,總時間複雜度為o(m+n)

參考推薦:

knuth-morris-pratt algorithm(wikipedia)

knuth-morris-pratt algorithm(string matching)

knuth-morris-pratt string matching

KMP演算法 字串匹配

kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...

KMP字串匹配演算法

kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...

KMP字串匹配演算法

在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的第乙個字元與模式串p的第乙個字元進行匹配,若相等,則繼續比較s的第二個字元和p的第二個字元 若不相等,則比較s的第二個字元和p的第乙個字元,依次比較下去,直到得出最後的匹配...