一、以下为字符串和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个字符
字串 | B | B | A | B | B | C | A | C |
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
next[i] | 0 | 1 | 2 | 1 | 2 | 3 | 1 | 1 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
next[i] | -1 | -1 | 1 | -1 | -1 | 2 | 0 | 0 |
二、以下是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