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的第乙個字元,依次比較下去,直到得出最後的匹配...