KMP
1.简介
KMP算法目的是在主串中快速找到一个字串
快速:并非一位一位比较后发现不匹配然后后移一位
字串:此处我们以后叫模式串
2.KMP使用的例子
红色框住是完全匹配部分,蓝色是最大公共前后缀
当字符发生不匹配时(红色框外第一对,主串B!=模式串A)开始在完全匹配部分找最大公共前后缀
下一步,将前缀移动到后缀,然后在下一个发生不匹配的字符位置之前完全匹配部分找最大公共前后缀
当模式串长度超出主串时,匹配失败
另一个成功案例:
运用KMP算法查找字串在效率上有了极大的提升
3.公共前后缀是什么?怎么找?
公共前后缀:
模式串中完全匹配部分 相同的地方
其特点是 前缀从前往后数 后缀从后往前数
例如ABCD 前缀是A AB ABC ABCD而后缀是D CD BCD ABCD
最大公共前后缀:
顾名思义,最大公共前后缀就是公共前后缀中最大的一串。
公共前后缀应该在比较指针(主串和模式串不一样的字符)左边开始找
4.next数组
既然我们知道了KMP算法,那么如果我们要用代码实现,我们还需要知道next数组,next数组的意思就是下一步应该如何做,我们应该怎么对模式串进行移动
一些名词解释:
1号位,2号位:指的是完全匹配部分的第一个,第二个
当前位置:指的是比较指针的位置就是匹配发现字符不相同的(首个)位置
规律:当最大公共前缀为n时,n+1号位与主串当前位进行比较
ps:这里一般从下标1开始记录
此时所得的next数组的值就是对应几号位的值了
比如这里
下标 0 1 2 3 4 5 6 7 8 9 10 11 12
next 不计 0 1 1 2 3 4 2 2 3 4 5 6
如果我们可以由前几位的next数组值得到下一位的next的值,通过这种递推的方式我们可以得到求next数组的代码
假设我们已知next[j]=t
分析:
代码:
void getNext(Str substr,int next[])
{
int j=1,t=0;
next[1]=0;
while(j<substr.length)
{
if(t==0||substr.ch[j]==substr[t])
{
next[j+1]=t+1;
++t;
++j;
}else t=next[t];
}
}
5.nextval数组
若出现特殊情况,我们可以对KMP算法进行优化
递推关系分析:
j=1,nextvval=0
j>1 Pj!=Pnext[j],nextval[j]=next[j]
Pj=Pnext[j],nextval[j]=nextval[next[j]]
代码:
void getNextval(Str substr,int nextval[])
{
int j=1,t=0;
nextval[1]=0;
while(j<substr.length)
{
if(t==0||substr.ch[j]==substr.ch[t])
{
if(substr.ch[j+1]!=substr.ch[t+1])
nextval[j+1]=t+1;
else
nextval[j+1]=nextval[t+1];
++t;++j;
}else t=nextval[t];
}
}
6.KMP算法的实操
next数组
void getNext(Str substr,int next[])
{
int j=1,t=0;
next[1]=0;
while(j<substr.length)
{
if(t==0||substr.ch[j]==substr[t])
{
next[j+1]=t+1;
++t;
++j;
}else t=next[t];
}
}
int KMP(Str str,Str substr,int next[])
{
int i=1;j=1;
while(j<str.length &&j<=substr.length)
{
if(j==0||str.ch[i}==substr.ch[j])
{++i;++j;}
else {j=next[j];}
}
if(j>substr.length)
return i-substr.length;
else
return 0;
}
nextval数组:
void getNextval(Str substr,int nextval[])
{
int j=1,t=0;
nextval[1]=0;
while(j<substr.length)
{
if(t==0||substr.ch[j]==substr.ch[t])
{
if(substr.ch[j+1]!=substr.ch[t+1])
nextval[j+1]=t+1;
else
nextval[j+1]=nextval[t+1];
++t;++j;
}else t=nextval[t];
}
}
int KMP(Str str,Str substr,int nextval[])
{
int i=1;j=1;
while(j<str.length &&j<=substr.length)
{
if(j==0||str.ch[i}==substr.ch[j])
{++i;++j;}
else {j=nextval[j];}
}
if(j>substr.length)
return i-substr.length;
else
return 0;
}