kmp算法的优化

来源:互联网 发布:java.util jar包 编辑:程序博客网 时间:2024/06/05 15:19

下面我们来说一下代码的优化。大家先看图:
            
        我们新设置了一个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];//
  }
 }
}
static void getnextval(const char*sub,int *next,int *nextval)
{
 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++;
 }
}
//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];
  }
 }
 free(next);
 free(nextval);
 if(j >= lensub)//找到了
 {
  return i-j;
 }
 else
 {
  return -1;
 }
}
标红的位置是相对于kmp算法,它优化之后添加的代码。