本文細緻分析了kmp演算法高效的原因以及kmp演算法的實現原理;
原始碼github位址(這是我自己實現的相關演算法(目前有排序演算法和kmp演算法),其中用到的資料結構也是自己實現的一套api,包括鍊錶、棧、佇列、樹、圖等內容,完善ing~)
kmp演算法是一種高效(線性時間)的字串匹配演算法;
kmp演算法之所以高效是因為它充分利用了模式字串本身的資訊以及匹配問題的特點;(感覺任何一種高效演算法都是通過充分利用已知資訊(包括計算得到的訊息和問題本身提供的資訊),避免無用的計算,從而實現高效);
原因一:
kmp演算法充分利用模式字串本身的資訊體現在它會根據模式字串計算出乙個陣列,這個陣列是什麼以及為什麼要計算乙個陣列a以及如何計算?,且看下文一一道來(理解了kmp高效的真正原因,才能深入理解kmp演算法**,畢竟,**背後是解決問題的思想~從思想入手看**,就是從本質出發看現象,而從**入手看思想,就有一點點難啦~廢話有點多,入正題!);
原因二:
kmp演算法充分利用了匹配問題的特點,舉個例子,比較好理解:
在上圖中,待匹配字串中v所指向的字元與模式字串中對應位置上的字元不匹配,接下來將向右移動模式字串;
以上例子表明,匹配問題的中無法避免的乙個操作就是回溯,所謂回溯就是當發生不匹配時,我們需要推翻已經匹配了部分,開始新的匹配;但是問題來了,從**開始新的匹配呢?普通實現演算法是將模式字串右移一位,然後繼續匹配; 我們按照普通思路來看這個匹配過程:下一步a將和b匹配(注意:a和b匹配表示模式字串的a字元和待匹配字串裡的b字元匹配~):
然後發現不匹配,之後再向右移動,a和a匹配;之後b和b匹配;a和a匹配;最終到達了下圖位置:
注意,在到達這個位置時,我們進行了5次字元間的比較;最後比較又停在了原來發生不匹配的地方;
我們來觀察這個過程的實質,其實就是從左到右的過程:
而拋開最後乙個字母不同(正是它們的不同導致匹配中斷),前5個字母是相同的!為什麼會相同呢?因為它們經過了匹配檢測呀!(這是一句廢話,但是這句廢話會引出a處的答案~):也就是說,當經過一段匹配後發生了不匹配的情況,之後進行的匹配就相當於已經匹配的部分模式字串自身和自身錯開一位後進行匹配,我把它稱為「自匹配」;顯而易見的乙個問題就是,匹配過程中會發生不少這樣的由於不匹配而引發的模式字串」自匹配」情況;這就是匹配問題的特點:在匹配過程中發生不匹配後所進行的匹配過程是已匹配部分字串的「自匹配」~;
既然「自匹配」是一種重複計算的過程,而該過程中使用的字串都是模式字串的一部分(更準確的說是模式字串從0位開始的子串):那麼我們就可以計算一遍而避免在匹配過程中頻繁重複計算!這就是a處要計算乙個陣列的原因~;
那麼這個a陣列到底是什麼呢?我們希望當發現圖1不匹配時,直接轉到圖3而跳過中間過程(這一過程其實就是自匹配的過程),可是怎樣算跳過了呢?其實就是b和a匹配(當x和y發生匹配,那麼x之前的字元和y之前的字元就一定是匹配的呀~)也就是當pattern[5]與s[x]發生不匹配時,下一次直接將pattern[3]與s[x]匹配;之所以這樣做,是因為我們通過「自匹配」知道pattern[0-2]一定與s[(x-3)-(x-1)]是匹配的;也就是說,a陣列記錄的資訊將提示我們當發生不匹配後,下一次進行匹配檢測的字元的索引~(至此,a是什麼以及為什麼都已解釋,接下來,就是如何計算a了~)
首先引入字首和字尾的概念:
對於字串x=yz;y、z也是字串;y稱為x的字首,z稱為x的字尾;當y不為空時,我們成z為真子字尾;
通過模式字串p計算陣列a的過程,就是尋找字串p[0-x]的特殊真子字尾的過程,該字尾的特殊性體現在它同樣也是模式字串的乙個字首;
(非常重要!!!)例如:a[x]等於y,就表示a[0-x]的特殊字尾的長度為y(也就是該字尾是a[0-(y-1)]),該式也表示當模式字串中下標為x+1的字元與對應位置上的字元不匹配時,下一次與待匹配字串對應位置上的字元進行比較的模式字串下標為y;
private
static
int getmoveinfo(char pattern)
/*退出時,要麼matchednum=0,即沒有發生匹配,也就是當前子串
pattern[i]沒有這樣的特殊子字尾;要麼是存在這樣的字尾*/
if(pattern[matchednum]==pattern[i])
info[i]=matchednum;//記錄模式字串p[0-i]的滿足要求的字尾長度
}return info;
}
在明白了a陣列是什麼、為什麼以及怎樣計算後,接下來就是kmp演算法的第二部分:匹配字串~;
public
static
void
match(string pattern, string source)
if(p[matchednum]==s[i])//如果對應位置上的字元是匹配的,那麼更新matchednum;
matchednum++;
if(matchednum==patternlength)}}
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的第乙個字元,依次比較下去,直到得出最後的匹配...