【KMP】演算法,未改進C++
首先是部分入門解釋:
1:求next陣列
當我們假設 模式串patten 為 aaabc時,
a a a b c
對應的 NEXT陣列為:
-1 0 1 2 0。
Next 陣列的含義:
求next陣列的時候,對於模式串的 J 位置 ,考察patten[ 0 ].到patten[j-1]組成的字串 最長且相等的字首和字尾。
假設最大相等字首和字尾長度為k,則有k使得 p[0]p[1]p[2]......p[k-2]p[k-1] = p[j-k]p[j-k+1]......p[j-2]p[j-1]。
先理解 字首 和 字尾,例 "aaabc" 字串的字首,字尾各有4種,相互獨立的。
字首 字尾
a a a b c
a a a b c
a a a b c
a a a b c
字首不包含 最後一個字元,
字尾不包含 第一個字元。
patten[0]前無字元,亦無後綴,所以next[0]=-1;表示不存在。
patten[1],在patten[0]~patten[0]找前後綴,均為空,next[1]=0;
patten[2],最長相等字首 'a',字尾為 'a'
patten[3],最長相等前後綴為 ‘aa’和‘aa’ ( 即字首 patten[0]patten[1],字尾 patten[1]patten[2])next[3]=2;
patten[4],字尾中含有 patten[3]=b,字首沒有 ‘b’,next[4]=0;
求該陣列過程如下:
演算法解釋如下:(關於回溯過程的解釋,說有些囉嗦,可以自己求一下,我的過程在最下面的貼圖上)
2 :KMP解釋
在BF暴力演算法中,假如從文字串的第 i 個字元來開始於模式串匹配。當匹配到模式串的第j位發現失配
即text[i+j] != patten[j]的時候,我們又從文字串的第i+1個位置來重新開始匹配。
可以看到每次失配之後,我們需要從文字串的下一個位置[ i+1 ]匹配,模式串從第一個字元重新開始於文字串匹配。並且在已經知道很多字元都配不上的情況下,還要這樣一個一個字元移動著去匹配,是非常浪費時間的。
假設文字串長為 n,模式串長為 m,BF暴力窮舉方法時間複雜度O(n*m),
而KMP演算法的實質就是,當遇到text[i+j] != patten[j]的時候,但是我們知道模式串中的 0~j-1 位置上的字元已經於i ~ i+j-1位置上的字元是完全匹配的。這樣我們可以在 0 ~ (j-1) 中找到一個字首A和字尾B相等並且最長的那個串,然後將A移動到B的位置再開始重新匹配即可。
這樣就減少了一些不必要的匹配。時間複雜度O(n+m)
借用其他博主的圖片和字串
準備好next陣列後開始kmp匹配,開始匹配位置 i=0,可以看到,前面的紅色黃色處均匹配,在藍色標(J=5)記處不匹配,藍色處字元對應的next陣列值為 2 ,說明 藍色字元C前面最長相等的前後綴為 a b,長度為2,因為紅色格子表示前後綴相等,所以把模式串划過去,直接讓 黃色格子 a 直接對準 上次藍色格子 C對應的文字串位置
模式串滑過去後如圖,這樣就避免了BF演算法中的 i=0匹配失敗,繼續匹配不可能匹配的 i=1,i=2兩個位置,恰好移動後,模式串和文字串匹配,假設模式串和文字串不匹配,模式串就繼續滑動。
程式碼如下
/* KMP演算法
未改進的
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1000; //假設最長字串長度
char text[maxn]; //文字串(目標串 被檢測)
char patten[maxn]; //模式串
int next[maxn]; //模式串的 next陣列
/*
*/
void GetNext(){ //獲取 next陣列
int Len_p=strlen(patten);
next[0]=-1;
int k=-1,j=0;
while(j<Len_p){
if(k == -1 || patten[j] == patten[k]){
++k; ++j;
next[j]=k;
}else{
k=next[k];
}
}
}
int KMP(){ //KMP演算法
int Addr=-1,i=0,j=0;
int Len_p=strlen(patten),Len_t=strlen(text);
while(i<Len_t){
if(j == -1 || text[i] == patten[j]){
++i; ++j;
}else{
j=next[j];
}
if(j == Len_p){
return i-Len_p;
break;
}
}
return Addr;
}
int main(){
scanf("%s%s",patten,text);
GetNext();
for(int i=0;i<strlen(patten);i++){
printf("%d ",next[i]);
} printf("\n");
printf("%d",KMP());
return 0;
}
執行如下:
第一行輸入 模式串 asd,第二行輸入文字串 asdf,第一行結果是模式串的next陣列,第二行為模式串第一次出現在文字串的位置
求模式串“aaabc”的next陣列的演算法每一步
引用參考https://blog.csdn.net/suguoliang/article/details/77460455#commentBox
博主:黑脈金