串的朴素算法和KMP模式匹配算法
串的朴素算法
(BF算法又称暴力搜索):首先待匹配串与模式串首先左对齐,然后从左向右开始逐个进行匹配,如果出现失配情况,则从待匹配串下一个字符开始进行匹配,直到模式串匹配成功。
例如:
待匹配串:a b d a b c a b
模式串 :a b c
开始进行匹配:
BF算法代码:
串的KMP模式匹配算法
核心思想为利用模式串自身的特点,若出现失配情况,则让模式串返回适当的位置,待匹配串不进行移动,若是一味的让模式串返回头部,则很可能会进行很多没有价值的运算,浪费了之前运算得到的反馈信息。
例如:
待匹配串:a b c a b c a b d a b
模式串 :a b c a b d
此时,我们可以发现,我们从模式串中可以发现,第一位的a肯定不等于第二位的b以及第三位的c,而我们在(1)已经得出了两者前五位是相等的,所以我们(2)(3)是没有必有的,肯定不会匹配成功。
这时我们可以让第六位出现失配情况时,直接让模式串指向第三位的c和待匹配串的第六位的c进行匹配,成功利用(1)得到的反馈信息,避免(2)(3)的无效计算。
核心思想:模式串返回的适当位置通过调用函数输出为一个数组next。
KMP算法代码:
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int *getnext(const char *sub)
{
int len = strlen(sub);
int *next = (int *)malloc(len*sizeof(int));
next[0] = -1;
next[1] = 0;
int j = 1;
int k = 0;
while(j+1<len)
{
if(k==-1 || sub[j]==sub[k])//next[j+1] = k+1
{
next[++j] = ++k;
}
else
{
k = next[k];//*****
}
}
return next;
}
static int *getnextval(const char *sub)
{
int len = strlen(sub);
int *next = (int *)malloc(len*sizeof(int));
int *nextval = (int *)malloc(len*sizeof(int));
next[0] = -1;
next[1] = 0;
int j = 1;
int k = 0;
while(j+1<len)
{
if(k==-1 || sub[j]==sub[k])//next[j+1] = k+1
{
next[++j] = ++k;
}
else
{
k = next[k];//*****
}
}
//获取修正的next值,去掉无效的回退
nextval[0] = -1;
for(int i=1;i<len;i++)
{
if(sub[i] == sub[next[i]])
{
nextval[i] = nextval[next[i]];
}
else
{
nextval[i] = next[i];
}
}
free(next);
return nextval;
}
//kmp:1.o(n+m);2.i不回退
int kmp(const char*str,const char *sub,int pos)//o(n+m)
{
int i = pos;
int j = 0;
int lenstr = strlen(str);
int lensub = strlen(sub);
int *next = getnext(sub);
int *nextval = getnextval(sub);
for(int i=0; i<lensub; i++)
{
cout << next[i] << " ";
}
cout << endl;
while(i<lenstr && j<lensub)
{
if(j==-1 || str[i]==sub[j])
{
i++;
j++;
}
else//失配
{
//kmp i不回退 //i = i-j+1;
j = next[j];
}
}
free(next);
if(j >= lensub)
{
return i-j;
}
else
{
return -1;
}
}
int main()
{
char *str = "abcdeabcdf";
char *sub = "abcdeabcdf";
printf("%d\n",kmp(str,sub,0));
return 0;
}