KMP算法
Next数组储存的是前j-1个字符的匹配 即a[0]a[1]a[2]a[3]…a[k-1]和a[j-k]a[j-k+1]…a[j-1] 所能匹配的k的最大值。
Next数组的求解:
( 1 )next[0]=-1,next[1]=0(j=1,在1~j-1的位置上没有字符,属于其他情况)。
( 2 )如果next[j]=k,表示有“a[0]a[1]a[2]a[3]…a[k-1]”=“a[j-k]a[j-k+1]…a[j-1] ” 这样的话 则有:
1.若a[k]=a[j],即有“a[0]a[1]a[2]a[3]…a[k-1]a[k]”=“a[j-k]a[j-k+1]…a[j-1]a[j]” 即有next[j+1]=k+1.
2.若a[k]!=a[j],说明a[j]之前不存在长度为next[j]+1的子串和开头字符起的子串相同此时应该将k回退 寻找有没有长度较短的子串和开头字符起的子串相同。此时的前k个字符已经符合“a[0]a[1]a[2]a[3]…a[k-1]”=“a[j-k]a[j-k+1]…a[j-1] ”,故从next[k]进行搜索 直到不存在可以匹配的子串,即此时k=next[k];
代码实现:
void GetNext()
{
int j,k;
j=0;k=-1;
next[0]=-1;
while(j<strlen(a))//a为模式串
{
if(k==-1||a[j]==a[k])
{
j++;k++;
next[j]=k;
}
else k=next[k];
}
}
( 二 )KMP算法匹配过程
我们以目标串“aaaaab”和模式串“aaab”为例
先求出模式串“aaab”的next数组:
j | 0 | 1 | 2 | 3 |
b[j] | a | a | a | b |
next[j] | -1 | 0 | 1 | 2 |
从开头进行匹配,当j=3时,发现匹配不成功
通过图我们不难得出a[j-1]a[j-2]=b[j-1]b[j-2]
而我们知道next[3]=2;即b[j-2]b[j-1]=b[0]b[1]
因此我们可以不让i动,而j后退,即使a[j-1]a[j-2]与b[0]b[1]对准,此时j=2=next[3]
继续进行如上匹配,可发现j=3时与目标串发生冲突,这时重复上述操作,可使j=2而i不变
最终字符串得以匹配,可以从这一般推到特殊,我在这里就不做过多说明了
模式如下:
i=0;j=0;
while(a和b都没有扫描完)
{
if(j=-1或者他们所指的字符相同)
i和j分别增1;
else
i不变,j回退到j=next[j];
}
if(j超界) 返回i-b的长度
else 返回-1
对应代码如下:
int KMP()
{
int i,j;
while(i<lena&&j<lenb)
{
if(j==-1||a[i]==b[j])
{
i++;
j++;
}
else
j=next[j];
}
if(j>=lenb)
return i-lenb;
else
return -1;
}