网上不少KMP算法的实例和讲解,很多大神也对此进行了详细的讲解,作为一名大一的新接触算法的人而言,我对此感觉很高深,而且有些不耐烦看长篇大论的文章。
下面附上一个next计算的算法不错的博客,我就是从这里面学到的next算法
http://www.cnblogs.com/yjiyjige/p/3263858.html
这篇博客使用java编写的KMP算法,我使用的是C语言,对于初学者应该比较好懂
我先把自己的KMP算法打到这里,然后再慢慢分析
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 100
#define MINSIZE 30
void getNext(char sonString[MINSIZE], int next[MINSIZE]);
void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE]);
int main()
{
char parentString[MAXSIZE]; //主串
char sonString[MINSIZE]; //子串
printf("please input parent string:\n");
scanf("%s", parentString);
fflush(stdin); //清空缓冲区
printf("please input son string:\n");
scanf("%s", sonString);
fflush(stdin);
int *next = (int *) malloc(sizeof(int) * strlen(sonString)); //申请动态内存用于储存next
getNext(sonString, next); //获取next数据的函数
KMP(parentString, sonString, next); //执行KMP的算法
return 0;
}
void getNext(char sonString[MINSIZE], int next[MINSIZE])
{
char sonStringTemp[MINSIZE];
strcpy(sonStringTemp, sonString); //使用一个临时数组来复制子串的值,主要是防止操作的过程中对原来的数组产生影响
int i, j;
j = 0;
i = -1;
next[0] = -1; //这里是先将第一个元素设置为一个-1,可以理解成一个标志性的变量
//while循环里的代码建议多采用debug几次,慢慢就会明白代码的意思了,不得不承认这是一个很漂亮的算法
while(j < strlen(sonStringTemp) - 1)
{
if(i == -1 || sonStringTemp[j] == sonStringTemp[i])
next[++j] = ++i;
else
i = next[i];
}
}
void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE])
{
int i, j;
i = 0;
j = 0;
while(j<(int)strlen(sonString) && i<(int)strlen(parentString))
{
if(j == -1 || sonString[j] == parentString[i])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if(i>=strlen(sonString))
printf("success %d\n", i-j+1);
else
printf("no this data\n");
}
我么先来看看next里的数据是怎么得到的
void getNext(char sonString[MINSIZE], int next[MINSIZE])
{
char sonStringTemp[MINSIZE];
strcpy(sonStringTemp, sonString); //使用一个临时数组来复制子串的值,主要是防止操作的过程中对原来的数组产生影响
int i, j;
j = 0;
i = -1;
next[0] = -1; //这里是先将第一个元素设置为一个-1,可以理解成一个标志性的变量
//while循环里的代码建议多采用debug几次,慢慢就会明白代码的意思了,不得不承认这是一个很漂亮的算法
while(j < strlen(sonStringTemp) - 1)
{
if(i == -1 || sonStringTemp[j] == sonStringTemp[i])
next[++j] = ++i;
else
i = next[i];
}
}
很有意思的是KMP算法里是防止回溯所带来的时间开销,而在求next的时候却在使用回溯来实现对next进行赋值,一般在一个KMP算法中会对next进行事先的约定,一般而言,是不使用数组的0号位置来存储数据的,但是这里为了减少对字符串的操作(个人认为C语言的字符串的操作太不方便),我们使用0号位置开始存储数据。
对next我们约定如下
对于while循环里的代码实际上就是一个“回溯的算法”,对于每次if语句里的判断不对的时候,i就会通过next数组向前回溯,然后直到找到和if语句里相匹配的位置。这里建议使用debug多进行几次就可以看出来了,推荐的使用的判断字符串
aabcaaabcad可以很好的测试next。
你可以先看next怎么用的,然后输出next里的数据,可以先不查找,先把next弄懂再进行下面的查找操作。
我们再来看一下KMP算法的查找部分
void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE])
{
int i, j;
i = 0;
j = 0;
while(j<(int)strlen(sonString) && i<(int)strlen(parentString))
{
if(j == -1 || sonString[j] == parentString[i])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if(i>=strlen(sonString))
printf("success %d\n", i-j+1);
else
printf("no this data\n");
}
如果明白KMP算法的原理,看这段代码应该很简单,需要注意的是strlen返回的是一个无符号整形,这里要使用强制类型转换。
本人也是刚刚学习的KMP算法,如有疏漏敬请指出。