KMP算法学习笔记

一、以下为字符串和next数组均从1开始计数

next[i]=j   含义:前i-1个字符组成的子串最长公共前后缀长度是j-1

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count=0;//便于理解,与功能无关,可以删除
void get_next1(char *p,int lp,int *next)
{
  int i=1,j=0;
  next[1]=0;
  while(i<lp)
  {
    if(j==0||p[i]==p[j])
    {
      next[++i]=++j;
    }
    else
    {
      j=next[j];
    }
  }
    
}
  
 
int kmp1(char *s,int ls,char *p,int lp)
{
  int *next=(int *)malloc(sizeof(int)*(lp+1));
  get_next1(p,lp,next);
  
  int i=1,j=1;
  while(i<ls && j<lp)
  {
    if(j==0||s[i]==p[j])
    {
	//以下打印为了方便理解,与功能无关,可以删除
		if(j==0)
			printf("第%d次比较:i=%d,j=%d\n",++count,i,j);
		else
			printf("第%d次比较:i=%d,j=%d,s[%d]=%c,p[%d]=%c\n",++count,i,j,i,s[i],j,p[j]);
	//以上打印为了方便理解,与功能无关,可以删除
      	i++;
      	j++;
    }
    else 
	{
		j=next[j];
		//以下打印为了方便理解,与功能无关,可以删除
		printf("第%d次比较:j回退到:%d\n",++count,j);
		//以上打印为了方便理解,与功能无关,可以删除
	}
  }
  if(j==lp) return i-j+1;
  else return -1;
}
 
int main() {
  
  char s[]="0AABBCBBABCBBABBCACCD";
  char p[]="0BBABBCAC";
  printf("%d",kmp1(s,strlen(s),p,strlen(p)));
 
  return 0;
}

以下为程序输出内容:

第1次比较:j回退到:0
第2次比较:i=1,j=0
第3次比较:j回退到:0
第4次比较:i=2,j=0
第5次比较:i=3,j=1,s[3]=B,p[1]=B
第6次比较:i=4,j=2,s[4]=B,p[2]=B
第7次比较:j回退到:2
第8次比较:j回退到:1
第9次比较:j回退到:0
第10次比较:i=5,j=0
第11次比较:i=6,j=1,s[6]=B,p[1]=B
第12次比较:i=7,j=2,s[7]=B,p[2]=B
第13次比较:i=8,j=3,s[8]=A,p[3]=A
第14次比较:i=9,j=4,s[9]=B,p[4]=B
第15次比较:j回退到:2
第16次比较:j回退到:1
第17次比较:j回退到:0
第18次比较:i=10,j=0
第19次比较:i=11,j=1,s[11]=B,p[1]=B
第20次比较:i=12,j=2,s[12]=B,p[2]=B
第21次比较:i=13,j=3,s[13]=A,p[3]=A
第22次比较:i=14,j=4,s[14]=B,p[4]=B
第23次比较:i=15,j=5,s[15]=B,p[5]=B
第24次比较:i=16,j=6,s[16]=C,p[6]=C
第25次比较:i=17,j=7,s[17]=A,p[7]=A
第26次比较:i=18,j=8,s[18]=C,p[8]=C
11

这是方法1(绿色)和方法2(橘色)求next数组的结果:

方法1:next[i]=j   含义:前i-1个字符组成的子串最长公共前后缀长度是j-1

方法2:没看懂,但是也是看的前i-1个字符

字串BBABBCAC
下标12345678
next[i]01212311
下标01234567
next[i]-1-11-1-1200

二、以下是2016年软件设计师KMP算法题,next数组含义我也没搞明白是啥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*求next[]的值*/
int count=0;//便于理解,与功能无关,可以删除
void get_next( int *next, char *s, int ls) 
{
  int i=0,j=-1;
  next[0]=-1;/*初始化next[0]*/
  while(i < ls)
  {/*还有字符*/
    if(j==-1 || s[i]==s[j])
    {/*匹配*/
        j++;
        i++;
        if( s[i]==s[j])
            next[i] = next[j];
        else
            next[i] = j;
    }
      else
        j = next[j];
  }
}
int kmp( int *next, char *t ,int lt,char *s,  int ls )
{
 
  int i= 0,j =0 ;
  while (i < lt && j<ls)
  {  
        if( j==-1 || t[i]==s[j] )
        {  
            //以下打印为了方便理解,与功能无关,可以删除
            if(j==-1)
                printf("第%d次比较:i=%d,j=%d\n",++count,i,j);
            else
                printf("第%d次比较:i=%d,j=%d,t[%d]=%c,s[%d]=%c\n",++count,i,j,i,t[i],j,s[j]);
            //以上打印为了方便理解,与功能无关,可以删除
            i ++ ;
            j ++ ;
            
        } 
        else
        {
             j =next[j];
            //以下打印为了方便理解,与功能无关,可以删除
            printf("第%d次比较:j回退到:%d\n",++count,j);
            //以上打印为了方便理解,与功能无关,可以删除
        }
  }
  if (j >= ls)
            return i-j ;
  else
        return -1;
}
 
int main() {
  char t[]="AABBCBBABCBBABBCACCD";
  char s[]="BBABBCAC";
  int *next=(int *)malloc(sizeof(int)*(strlen(s)+1));
  get_next( next, s, strlen(s)) ;
  printf("%d",kmp(next,t,strlen(t),s,strlen(s)));
  return 0;
}

以下为程序输出内容:

第1次比较:j回退到:-1
第2次比较:i=0,j=-1
第3次比较:j回退到:-1
第4次比较:i=1,j=-1
第5次比较:i=2,j=0,t[2]=B,s[0]=B
第6次比较:i=3,j=1,t[3]=B,s[1]=B
第7次比较:j回退到:1
第8次比较:j回退到:-1
第9次比较:i=4,j=-1
第10次比较:i=5,j=0,t[5]=B,s[0]=B
第11次比较:i=6,j=1,t[6]=B,s[1]=B
第12次比较:i=7,j=2,t[7]=A,s[2]=A
第13次比较:i=8,j=3,t[8]=B,s[3]=B
第14次比较:j回退到:-1
第15次比较:i=9,j=-1
第16次比较:i=10,j=0,t[10]=B,s[0]=B
第17次比较:i=11,j=1,t[11]=B,s[1]=B
第18次比较:i=12,j=2,t[12]=A,s[2]=A
第19次比较:i=13,j=3,t[13]=B,s[3]=B
第20次比较:i=14,j=4,t[14]=B,s[4]=B
第21次比较:i=15,j=5,t[15]=C,s[5]=C
第22次比较:i=16,j=6,t[16]=A,s[6]=A
第23次比较:i=17,j=7,t[17]=C,s[7]=C
10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值