目录
KMP算法的改进点
在原始的KMP算法中,子串已经不会回退到起始点,但是还有一种特殊情况,首先看下表(已经求得next数组)。
模式串 | A | A | A | A | A | B |
j | 0 | 1 | 2 | 3 | 4 | 5 |
next[j] | -1 | 0 | 1 | 2 | 3 | 4 |
如果当j等于4的时候,发生不匹配,因为next[4]=3,则需要将j回溯到3进行比较;又因为next[3]=2,则又要将j回溯到2的位置进行比较,j需要一次在4,3,2,1,0的位置上进行比较,而模式串在0到4上的内容是相等的,因此比较聪明的做法是当在j=4发生不匹配的时候,直接将j回溯到0,直接跳过1到3的多余的比较,这就是KMP算法改进的切入点。
nextval数组的手动求解
对于手动求解nextval数组,先可以求出next数组,然后再求nextval数组,首先先给出大家一个实例,见下表:
模式串 | A | B | A | B | A | A | B |
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
next[j] | -1 | 0 | 0 | 1 | 2 | 3 | 1 |
nextval[j] | -1 | 0 | -1 | 0 | -1 | 3 | 0 |
参照上表,给出nextval数组的一般步骤:
- 求出next数组;
- 当j=1时,另nextval[j]=-1,作为特殊标记;
- (记模式串为p)当p[j]不等于p[next[j]]时,另nextval[j]=next[j]
- 当p[j]==p[next[j]]时,另nextval[j]=nextval[next[j]]
这样,我们就得到了nextval数组,可以参照上面的例子,按照步骤尝试一遍,你会恍然大悟。
nextval数组的程序求解
nextval数组的求解和next数组的求解大同小异,只是在对next数组赋值的时候加一句判断的代码即可。
void getNextval(int *nextval,const char *sub)
{
assert(nextval!=NULL&&sub!=NULL);
nextval[0]=-1;
nextval[1]=0;
int j = 2;
int k = 0;
int len = strlen(sub);
while(j<len)
{
if(k==-1||sub[k]==sub[j-1])
{
++i;
++k;//已经得到next值
if(sub[j]!=sub[k])//进行判断
{
nextval[j]=k;
}
else
{
nextval[j]=nextval[k];
}
}
else
{
k=nextval[k];//k回溯
}
}
}