KMP 模板
#include<iostream>
#include<cstring>
#define maxn 100
using namespace std;
int next[maxn];
// next[j]存储的是当第j个字符匹配失败时,就将k模式串指针跳到next[j]处。故只有在匹配失败时才会用到next[] 中存储的值
void get_next(char *p){
int k=-1,j=0; //next[]数组的第一个值一定是-1,用-1“标记”第一个字符就匹配失败的情况。 j从0位开始遍历模式串,直到pl-1
int pl=strlen(p);
next[0]=-1; //next[]中存储的永远是-1
while(j<pl){ //j要从0遍历模式串直到pl。 因为在上面next[0]的值已经给出,故 j在while循环中实际从1开始遍历模式串,直到pl。
if(k==-1 || p[k] == p[j]){ //如果k==-1; 说明当前不匹配的是第二个(大括号里j++之后j就到达2了)字符,它前面只有第一个字符,故其前面的最大公共长度是0。
//所以此时next[1]=k++;(next[1]是第二个字符,k++ 之后等于0。)
k++; j++;
next[j]=k;
}
else
k=next[k];//求第二大长度
//若p[k] != p[j],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。 //个人小想法:若把p[k] == p[j]时得到
//的公共长度称为最大公共长度,便可以把k退一步得到的公共长度称为公共第二长长度了。哈哈。。。
}
}
int KMP_search(char *s,char *p){ //返回值是与模式串相同的子串在主串中的首字符的的下标。
int i=0,j=0; //i,j分别遍历主串s,模式串p。
int slen=strlen(s);
int plen=strlen(p);
while(i<slen && j<plen){ //使匹配结束的原因两个:(一) i<slen, (j>=plen),即主串被遍历完了,但即便这样也没有找到与模式串相同的子串。
//(二) j<plen, (s<slen),即主串还没有被遍历完,就找到了与模式串相同的子串。
//(三) i,j同时达到i>=slen,j>=plen,说明恰好在遍历到主串的最后一个最后一个字符时,找到与模式串相同的子串。
if(j == -1 || p[j] == p[i]){//j==-1说明是在第一个字符就不匹配的情况下产生的j=next[0],之后j==-1 ,既然第一个字符就不匹配,那么下一步就只能i、j均加1了。
//或说:j == -1表示又已经开始从头遍历模式串p,且第一个字符就匹配失败(next[0] == -1),接下来就只能有一种操作咯:i++; j++;
i++; j++;
}
else
j=next[j]; //当前字符不匹配时采取措施:j=next[j]。
}
if(j>=plen) return i-plen; //如果p>=plen,说明模式串被成功遍历完了一遍,即说明在主串中找到了与模式串相同的子串。
// else //如果至while循环结束,j都还是j<plen,说明在主串中最终都没有找到与模式串相同的子串。
return -1; //没有找到与模式串相同的子串,就返回-1。
}
int main(){
char s[maxn] = "abcdefgabcg"; //主串
char p[maxn] = "abcg"; //模式串
int position = KMP_search(s,p); //返回值是主串中与模式串相同的子串的首字符的下标值。
if(position == -1) cout<<"未找到"<<endl;
else cout<<"The positon of '"<<p<<"' in the '"<<s<<"' is "<<position<<endl;
}
KMP模板 代码解释
** KMP算法的思想网络上已有众多大神的讲解,小编便不再献丑了。因初学时应用之际对代码实现具有颇多疑惑,想必有许多朋友也是如此。现对KMP模板的代码进行了“逐条”解释,希望对您有所帮助。不当之处,敬请斧正。以下众大神之讲解对本人帮助颇多,现列举如下