声明:这是我学过KMP后整理的笔记,目的只是为了将来复习的时候能快速记起KMP的用法和代码实现。因部分内容感觉不需要整理所以这篇博客并不详细完整,如果是要学习KMP建议找其他大神的博客系统学习。否则看懵了我不负责哟~
KMP的作用:优化匹配字符串。
大致思想:
如在“ABCDABCDEFABCDABCDAG”(我们称之为被匹配字符数组)中搜索“ABCDABCDAG”(匹配字符数组),前面有两个重复的“ABCD”,不匹配的时候就不需要一个一个往后推,直接把前缀“ABCD”推到后缀“ABCD” 匹配的那个地方,从那里往后推就行。
上面那段话有点绕。反正我是明白了。
要实现这一思想首先要先检测匹配字符数组中有没有重复的部分(前缀和后缀)。检测的方法是给每一个字符赋NEXT值。举例如下:(注意在这个例子中字符数组“ABCDABCDEFABCDABCDAG”被当作匹配字符数组,就是短的那个)
ABCDABCDEFABCDABCDAG的NEXT值分别为-1 0 0 0 0 1 2 3 4 0 0 1 2 3 4 5 6 7 8 5
‘A’的值为-1是因为如果是0的话一旦不匹配就会不断跳转到0,即A本身。这样就死在那了。
对了,NEXT值的含义是如果不匹配那么会跳转到第几位。所以G的NEXT 值为5。
好吧,如果看到上面还是不记得为什么NEXT值是5==(一般不会这样的。)
因为发现到了G不匹配,就会搜索有没有前缀是ABCDABCDA。发现没有。于是检测有没有前缀是ABCDA。 发现有,于是G跳转到第五个。‘B’。
综上可见NEXT值的计算很简单。所以代码实现如下:
int ne[100];///这个数组中盛放的是匹配字符串的next值
void GetNext(char *a)///这个函数是为了标记匹配字符串的next值
{
int len = strlen(a);///先求字符串的长度,便于循环赋值
int i = 0, j = -1;
ne[0] = -1;
while(i < len)
{
if(j == -1 || a[i] == a[j])
{
ne[++i] = ++j;
}
else j = ne[j];
}
}
///实际上每求一个next值要循环两遍
然后就是根据NEXT值来简单快速匹配:
int KMP(char *a, char *b)
{
int lena = strlen(a);
int lenb = strlen(b);
int i = 0, j = 0;
while (i < lena && j < lenb)
{
if(j == -1 || a[i] == b[j])
{
j++;
i++;
}
else
j = ne[j];
}
if(j == lenb)
return i-j+1;
else
return -1;
}
///这个代码的结果:如果能匹配则返回匹配代码在被匹配代码中首字符的位置;如果不能匹配则返回-1
只要明白原理这两个代码是非常容易搞明白的。
下面是一个完整的最简单KMP code:
#include "cstdio"
#include "iostream"
#include "cstring"
using namespace std;
int ne[20];///这个数组中盛放的是匹配字符串的next值
void GetNext(char *a)///这个函数是为了标记匹配字符串的next值
{
int len = strlen(a);///先求字符串的长度,便于循环赋值
int i = 0, j = -1;
ne[0] = -1;
while(i < len)
{
if(j == -1 || a[i] == a[j])
{
ne[++i] = ++j;
}
else j = ne[j];
}
}
///实际上每求一个next值要循环两遍
int KMP(char *a, char *b)
{
int lena = strlen(a);
int lenb = strlen(b);
int i = 0, j = 0;
while (i < lena && j < lenb)
{
if(j == -1 || a[i] == b[j])
{
j++;
i++;
}
else
j = ne[j];
}
if(j == lenb)
return i-j+1;
else
return -1;
}
int main()
{
char s[100];///this is the main
char f[100];///this is the one to be found
scanf("%s", &s);
scanf("%s", &f);
GetNext(f);
cout << KMP(s,f) << endl;
return 0;
}
THE END.