这位大大的博客关于KMP的原理的讲解KMP算法的大致讲解
这位大大的一篇很长很长的关于KMP的细致讲解KMP细致讲解
建议看第一篇自己理解后,再去第二篇验证自己的想法,而且这两篇博客里面的东西稍有不同,建议自己先Code一遍,再看第二篇,我的注释也会帮助你理解KMP中的一些边界处理的事
看了好久的KMP几天终于可以真正的理解了,那个next数组中的一个递归的概念真的很厉害next[next[j]] 看了上面的那篇博主的解析,才恍然大悟,以下是本人对其算法的一些注释,一些细致方面的解释。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100
int next[MAX+1];
// next数组是从0开始的
// next[i] 表示的是 p[0..i] 这个串的 前缀和后缀的相同长度
// 注意:
// 后缀和前缀不能够重合,不然就没有办法跳转了,
// 就会造成每次前缀和后缀的最长的长度都是i+1,
// 所以有了next[1] = 0,而不是 next[1] = 1;
void getnext(char *p)
{
int j = 0;
next[0] = next[1] = 0;
// 遍历,得到next
for(int i=1; i<strlen(p); ++i) {
while( j>0 && p[i] != p[j] ) j = next[j];
if( p[i]==p[j] ) j++;
next[i+1] = j;
}
}
void search(char *s, char *p)
{
// j 表示 模式串当前比较的字符
int j=0;
// i 表示 当前比较的文本的字符
for(int i=0; i<strlen(s); i++) {
/*
* 当文本中的字符串不相等时,模式串根据next跳到要比较的字符串的位置
* 位置当然是相同相同的前缀和后缀的后一个
* next记录的是前缀和后缀相同的长度,而不是下标, 顾 j=next[j]即可
*/
while(j>0 && s[i]!=p[j]) j = next[j];
// 文本的字符等于模式串的字符则下标+1
if( s[i] == p[j] ) j++;
/*
* j 本来是字符比较的下标,因为在比较成功的前
* 一定会执行前面的的 if( s[i] == s[j] ) j++的,所以匹配成功的标志为
* j == strlen(p);
*/
if(j==strlen(p)) {
// i-j+1 是匹配成功的第一个字符串的位置
printf("%d\n", i-j+1);
// break;
j = next[j];
}
}
}
int main()
{
char *s = "babcbabcabcaabcabcabcacabc";
char *p = "abcabcacab";
getnext(p);
for(int i=0; i<strlen(p); i++)
printf("%d,", next[i]);
printf("\n");
search(s,p);
return 0;
}