KMP算法

来源:互联网 发布:股票经典书籍 知乎 编辑:程序博客网 时间:2024/05/01 02:52

 #include<string.h>
#include<stdio.h>


/*
一般的模式匹配算法
如主串为Z[]='abababc',模式串M[]='ababc'

ZL=strlen(Z),ML=strlen(M)

匹配时
使用i=0,j=0,则
当Z[i]==M[j]时i++,j++,否则i=i-j+1,j=0不变,这样直到确认匹配或者主串已经找完
*/
int locate(char *Z,char*M)
{
 int i,j,ZL,ML;
 i=0;
 j=0;
 ZL=strlen(Z);
 ML=strlen(M);
 while(i<ZL||j<ML)
 {

   if(Z[i]==M[j])
  {
   i++;
   j++; 
  }
   else
  {i=i-j+1;j=0;}

 }
 if(j==ML)
  {
   printf("locate:   匹配,位置为%d,即第%d个元素;",i-ML,i-ML+1);
   return j-ML;
 }
 else
  {
  printf("locate:   无匹配");
  return 0;
  }


}
/*
KMP算法解决的主要问题是模式匹配中的效率问题 (避免匹配过程回溯即从i++到i=i-j+1)

M[]='ababc',主串为Z[]='abababc'

比如说Z[4]='a',M[4]='c',(i=4,j=4)不匹配,按照上面的算法应该使得i=1,j=0
但是我们发现M的{M[0]==a,M[1]=b}与{M[2]=a,M[3]=b}是一样但{M[0]=a}与{M[1]=b}不一样
所以我们可以利用之前验证的结果
即{M[2],M[3]}与{Z[2],Z[3]}已经匹配了,故可以将{Z[2],Z[3]}与{M[0]==a,M[1]=b}的匹配过程跳过
即从i=4与j=2开始再进行匹配下去,

所以现在我们要解决的问题是确定当主串在匹配模式串M[j]不匹配时,我们怎么来确定
主串Z[i]应该与M[]的哪个元素开始匹配,这就是next函数的功能.
*/
int locate_next(char*Z,char *M,int next[])
{
 int i,j,ZL,ML;
 i=0;
 j=0;
 ZL=strlen(Z),ML=strlen(M);
 while(j<ML||i<ZL)
 {

   if(j==-1 || Z[i]==M[j])
  {

   i++;
   j++;
  }
   else
  {j=next[j];
  
  }

 }
 if(j==ML)
  {
   printf("locate_next:  匹配,位置为%d,即从第%d个元素开始;",i-ML,i-ML+1);
   return i-ML;
 }
 else
  {
  printf("locate_next:  无匹配");
  return 0;
  }


}


/*
当模式串如M[]='aaaab',匹配M[3]不成功时本来主串要再分别与M[2],M[1],M[0]进行匹配
但实际上M[3],M[2],M[1],M[0]均相等,故主串的Z[x+0],Z[x+1],Z[x+2],在判断Z[x+3]与
M[3]时已经确认了,所以可直接跳过进行Z[x+4]与M[0]的比较

*/

 


/*
改进的next_val
*/
void impro_next_val(char* M,int next[])
{
 int i,j,ML;
 i=0;j=-1;
 next[0]=-1;//用来表示第一个就不匹配的情况 
 ML = strlen(M);
 while(i<ML)
 {
  if(j==-1 || M[i]==M[j])
  { 
   
   i++;
   j++;
   if(M[i]!=M[j])
    next[i]=j;   
   else
    next[i]=next[j];/*模式串中连续相同的子串*/
   
  }
 else
     {
  j=next[j];  
  }
 }
 printf("/n next[]:  ");
 for(i=0;i<ML;i++)
  printf(" %d ",next[i]);
 printf("/n");

}

 

int main()
{
char *M="aaaac";
char *Z="baaacaaaac";
int next[6];
locate(Z,M);
impro_next_val(M,next);
locate_next(Z,M,next);
return 0;
}

原创粉丝点击