kmp算法是一种解决字符串匹配的算法。
1.具体思想:
匹配模板(Model):aabaaf
字符串(Str):aabaabaaf
进行匹配
a | a | b | a | a | b | a | a | f |
a | a | b | a | a | f |
字母f 与字母 b 发生冲突
下一次比较应该从b的位置开始比较
理论依据:kmp算法参考了一种最长相等前后缀的思想
2.前缀与后缀又是什么?
前缀:只包含首字母不包含尾字母的子串
后缀:只包含尾字母不包含首字母的子串
字符串 | 前缀 | 后缀 | 最长相等前后缀长度 |
a | 0 | 0 | 0(无前后缀) |
aa | a | a | 1(a) |
aab | aa,a | ab,b | 0 |
aaba | aab,aa,a | aba,ba,a | 1(a) |
aabaa | aaba,aab,aa,a | abaa,baa,aa,a | 2(aa) |
aabaaf | aabaa,aaba,aab,aa,a | abaaf,baaf,aaf,af,f | 0 |
kmp算法就是:查看冲突字符(f与b)右边的子串(aabaa)的最长相等前后缀(aa长度为2)来确定下一次比较的坐标(Model[2]==b)
所以KMP算法的关键:就是得到[0,1,0,1,2,0]这个前缀表(next数组)
1.初始化:类似表一aa
j(前缀末尾) | i(后缀末尾) | ||||
a | a | b | a | a | f |
0(next[0]=0) | 1(前后缀相等) |
2. 前后缀不等:类似表aab
a与b不等
逐个比较j-1(字符a右边的元素)与i(b)是否相等 若有则加1 若无则为0
j | i | ||||
a | a | b | a | a | f |
0 | 1 | 0 |
2. 前后缀等:类似表aaba
j | i | ||||
a | a | b | a | a | f |
0 | 1 | 0 | 1 | 2 | 0 |
void getNext(char *str,int *next)
{
//字符串长度
int length=strlen(str);
int i;//后缀末尾
int j=0;//前缀末尾 初始化为0
next[0]=0;//初始化next数组 因为只有一个字母时无前后缀
for(i=1; i<length; i++)
{
//前后缀不等的条件
while(j>0&&str[i]!=str[j])
{
j=next[j-1];
}
//前后缀相等的条件
if(str[i]==str[j])
{
j++;
}
next[i]=j;
}
}
#include<stdio.h>
#include<string.h>
void getNext(char *str,int *next)
{
//字符串长度
int length=strlen(str);
int i;//后缀末尾
int j=0;//前缀末尾 初始化为0 也是next中所填的坐标
next[0]=0;//初始化next数组
for(i=1; i<length; i++)
{
//前后缀不等的条件
while(j>0&&str[i]!=str[j])
{
j=next[j-1];
}
//前后缀相等的条件
if(str[i]==str[j])
{
j++;
}
next[i]=j;
}
}
int checkStr(char *str,char *model)
{
int lengthStr=strlen(str);
int lengthModel=strlen(model);
if(lengthStr==0)
{
return 0;
}
int i,j=0;
int next[6];
printf("%d ",lengthModel);
getNext(model,next);
for(i=0; i<lengthStr; i++)
{
while(j>0&&str[i]!=model[j])
{
j=next[j-1];//找前一个前缀表开始比较的位置
}
if(str[i]==model[j])
{
j++;
}
if(j==lengthModel)
{
return (i-lengthModel+1);
}
}
return -1;
}
int main()
{
char str[]="aabaaf";
char pk[]="aabaabaafaabaa";
int i;
int k=checkStr(pk,str);
printf("%d ",k);
int length=strlen(str);
for(i=k;i<k+length;i++)
{
printf("%c",pk[i]);
}
}