KMP演算法筆記

2021-08-13 03:02:19 字數 3088 閱讀 9263

kmp演算法是一種快速的字串匹配演算法,我們先從暴力字串匹配演算法講起看怎麼對其優化得到kmp演算法。

****這篇文章 

1、暴力字串匹配

有如下兩個字串:a:「abcabbcabc」和b:「adfabcabccabcadbcabca」,我們要在b中找到a的匹配位置,暴力匹配的做法就是:把a的第乙個元素與b的第乙個元素對齊並開始往後遍歷比較,遍歷的過程中只要有乙個字元不匹配,則將a往後移動一位,即將a的第乙個元素與b的第二個元素對其開始往後遍歷比較,以此類推。

如上述兩個字串a和b的匹配過程如下:

第乙個元素匹配,第二個元素d和b不匹配,那麼將a串往後移動一位繼續匹配如下:

再移動兩次後,來到了這個位置:

我們可以看到在比較c和b時發現不匹配,但是前面的abcab全是匹配的,而暴力匹配的做法是繼續將字串a移動一位,然後將兩個字串從頭開始匹配,知道遍歷到如下地方匹配完成:

因此得到的暴力匹配演算法如下:

int violentmatch(char* s, char* p)  

else

} //匹配成功,返回模式串p在文字串s中的位置,否則返回-1

if (j == plen)

return i - j;

else

return -1;

}

暴力匹配演算法的時間複雜度為o(m*n)其中m和n分別是兩個字串的長度

2、kmp演算法

kmp演算法從暴力匹配演算法經過優化得到,我們仔細看暴力搜尋演算法的移動,在上面第三張圖中,當b與c發生不匹配時,前面的abcab是已經匹配了的,如下:

既然前面的已經匹配過了,那麼我們就知道,此時只將a移動一位,肯定是不匹配的,通過觀察我們發現,應當將a移動到如下地方:

這樣就可以省掉了不比較的字元比較,即在某個字元匹配失敗時,前面的字串是匹配成功的,我們可以根據已經匹配成功的字串,得出下次的匹配從**開始。

我們可以看到,上面的字串之所以可以這樣移動,是因為前面已經匹配的字串abcab中,前面的首尾是一樣的,即都是「ab」,所以我們將字串a的首部直接移動到已經匹配了的地方,然後重新比較上次匹配失敗的字元。

那麼我們現在要做的就是求出a中當每個字母匹配失敗時,下次應該從**開始繼續匹配,將下標儲存在next陣列中,即若next[j]=k,表示在a中當下標j處的元素匹配失敗時,繼續從下標為k處開始匹配。

首先next[0]=-1,表示第乙個元素就匹配失敗,要同時移動a和b一項然後從新開始匹配

next[1]= 0 ,表示第二個元素匹配失敗時,從a的第乙個元素開始繼續匹配

那麼重點開始了,接著上面的,現在開始求next陣列:

next[j]的值與next[j-1]的值有關,原因如下:

①當在j處發生不匹配時,若next[j-1]=0,表示j-1的前面字串沒有首尾一樣的,那麼只用比較a[0]和a[j-1]

若a[0]=a[j-1],則next[j]=1,否則next[j]=0

②當在j處發生不匹配時,若next[j-1]=k,表示j-1前面的字串中,首部k個長度和尾部k個長度一樣,那麼我                    們需要比較a[k]和a[j-1],若a[k]=a[j-1],明顯此時j前面就有首部k+1個和尾部k+1個是一樣的,即                                 next[j]=k+1,即next[j]=next[j-1]+1

③那麼當a[k]≠a[j-1]時,該怎麼確定a[j]的值呢(我想很多人迷惑的是這個地方),我們看下圖:

當j處發生不匹配且a[k]

≠a[j-1]時,我們已知next[j-1]=k,即圖中a1=a2,那麼可以得到b2=b3。同理由k和next[k]可以得到圖中b1=b2,那麼就有b1=b3。

因此現在只需要比較a[j-1]與next[k]的大小就可以了,若相等,則next[j]=next[k]+1,否則繼續往後找。

那麼獲取next陣列的**如下:

void getnext(char* p,int next)  

else

} }

有了next陣列後,kmp演算法的**就比較容易了,**如下:

int kmpsearch(char* s, char* p)  

else

} if (j == plen)

return i - j;

else

return -1;

}

3、next陣列的優化:

如果當next[j-1]=a[k]且next[j]=a[j]時,不能直接使next[j]=next[j-1]+1,如下圖:

如果直接移動過去,明顯下乙個比較是不相等的,所以在構造next陣列時還需要一次判斷,**如下:

//優化過後的next 陣列求法  

void getnextval(char* p, int next)

else

} }

KMP演算法筆記

kmp演算法我是看july部落格學習,這裡只是做個筆記,詳細內容見july的blog kmp演算法的用途 有乙個文字串s和乙個模式串p,現在要查詢p在s中的位置。暴力匹配演算法需要對文字串s進行回溯,kmp演算法就是讓文字串不回退,只需要移動模式串j即可。kmp演算法大體思想 就是當s i p j ...

KMP演算法筆記

無聊開啟vjuge看了一眼,看到有乙個比賽是ac自動機,開啟看看順便xuexi一下子。需要 kmp複習一下感覺全忘了。附兩篇參考資料 和乙個練習題 include include include include include include include include include incl...

KMP演算法筆記

1.kmp演算法用於字串匹配。2.最直觀的字串查詢,是用兩次迴圈遍歷,演算法複雜度0 m n m為待查字串,n為需要查詢的子串。3.kmp演算法的目的為減少n維度。4.include include using namespace std void getnext const string ptr,...