下面我们来说一下代码的优化。大家先看图:
我们新设置了一个nextval数组,nextval[j]表示优化后的在j失配,它应该退回的位置。我们原来求解j回退位置k时,其实还是存在无用功。如果p[j]=p[k],而我们在j位置发生了失配,j回退到k的位置,结果它的字符和j一样,那就无意义啊,因为它肯定还是会失配的,只有不一样的时候,才有可能匹配成功。所以当p[j]=p[k]我们就需要继续转到k=next[k]的位置上,然后比较新的p[k]是否等于p[j]如果等于,我们就需要再继续走,直到退到的字符不等于p[j],或者退到无路可退,也就是k为-1了。我们再仔细思考一下如果p[k]=p[j],我们是不是可以直接让
nextval[j]=nextval[k],因为我们的思想是从低下标开始求对应nextval值,如果已经求到nextval[j]时,k位置对应的nextval值早就已经优化过了,它保证了如果在k发生失配,则它退回的位置要么对应的字符是不同的,要么就是-1,也就是无路可退了。如果p[j]和p[k]是不同的,那nextval[j]=k;
好,我们来看一下代码实现:
tatic void GetNext(const char*sub,int *next)
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int j = 1;//通过j求j+1的值
int k = 0;
while(j+1
{
if(k==-1 || sub[j]==sub[k])
{
next[++j] = ++k;
}
else
{
k = next[k];//
}
}
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int j = 1;//通过j求j+1的值
int k = 0;
while(j+1
{
if(k==-1 || sub[j]==sub[k])
{
next[++j] = ++k;
}
else
{
k = next[k];//
}
}
}
static void getnextval(const char*sub,int *next,int *nextval)
{
int lensub = strlen(sub);
nextval[0] = -1;
int j = 1;
int k ;
{
int lensub = strlen(sub);
nextval[0] = -1;
int j = 1;
int k ;
while(j
{
k=next[j];
if(sub[j]==sub[k])
{
nextval[j]=nextval[k];
}
else
{
nextval[j]=k;
}
j++;
}
}
{
k=next[j];
if(sub[j]==sub[k])
{
nextval[j]=nextval[k];
}
else
{
nextval[j]=k;
}
j++;
}
}
//KMP 算法特点:i不回退,时间复杂度O(n+m)
int KMP(const char *str,const char *sub,int pos)//O(n+m)
{
if(pos < 0)
{
return -1;
}
int lenstr = strlen(str);
int lensub = strlen(sub);
int i = pos;
int j = 0;
int *next = (int *)malloc(lensub*sizeof(int));
GetNext(sub,next);
int *nextval=(int*)malloc(lensub*sizeof(int));
getnextval(sub,next,nextval);
while(i
{
if(j==-1 || (str[i]==sub[j]))
{
i++;
j++;
}
else//i不回退,j退到next[j](即k位置)
{
j = nextval[j];
}
}
int KMP(const char *str,const char *sub,int pos)//O(n+m)
{
if(pos < 0)
{
return -1;
}
int lenstr = strlen(str);
int lensub = strlen(sub);
int i = pos;
int j = 0;
int *next = (int *)malloc(lensub*sizeof(int));
GetNext(sub,next);
int *nextval=(int*)malloc(lensub*sizeof(int));
getnextval(sub,next,nextval);
while(i
{
if(j==-1 || (str[i]==sub[j]))
{
i++;
j++;
}
else//i不回退,j退到next[j](即k位置)
{
j = nextval[j];
}
}
free(next);
free(nextval);
free(nextval);
if(j >= lensub)//找到了
{
return i-j;
}
else
{
return -1;
}
}
{
return i-j;
}
else
{
return -1;
}
}
标红的位置是相对于kmp算法,它优化之后添加的代码。