kmp算法粗略理解(仅总结个人理解以便复习)

对于kmp算法,还是建议大家看一下数据结构严蔚敏这本书,虽然文章很多但是感觉看了几十分钟的文章只是强调过程,没有强调目的,所以看完之后还是很晕的,这时你看一眼书可能就会理解了。本人纯属小白一个,写文章是为了日后复习,如有错误还请指出。

#include
#include
#include 

#define MAXS 80

typedef struct{
	char *ch;
	int length;
} HString; // 堆式顺序存储

void createString(HString &S){
	S.ch = new char[MAXS];
	gets(S.ch+1);
	S.length = strlen(S.ch+1); 
}

// 使用 KMP 算法进行模式匹配,字符比较次数 
int charCompKMP(HString S, HString T);

int main(){
	HString S, T;
	createString(S);
	createString(T);
	int num = charCompKMP(S, T);
	printf("%d", num); 
}

int charCompKMP(HString S, HString T){
    int next[1000];
    int j=1,t=0,i=1,sum=0;
    next[1]=0;
    while(j<T.length){
        if(t==0||T.ch[j]==T.ch[t]){
            next[j+1]=t+1;
            j++;
            t++;
        }
        else{
            t=next[t];
        }
    }
    j=1;
    while(i<=S.length&&j<=T.length){
    	if(j==0)
    	sum--;
       if(j==0||S.ch[i]==T.ch[j]){
           i++;
           j++;
       }
       else
       {
           j=next[j];
       }
       sum++;
       if(j>T.length)
       return sum;
   }

}


这是我们平时作业的一道题,求的是kmp算法比较的次数,next数组的目的其实就是算最长前后缀,并在进行字符串匹配的时候让模式串回溯到指定的位置,并且要让回溯的效率提高,aabaaa这个字符串计算公共前后缀到next数组里面就是 0 1 2 1 2 3。
kmp算法粗略理解(仅总结个人理解以便复习)_第1张图片

那么接下来说一下kmp算法,
按照我们大致的理解其实就是当主串与模式串匹配成功的时候i,j就会向后移,但是如果匹配不成功呢,就要回溯,那么回溯到哪里呢?假如失配这个字符前面最长前后缀的长度为length就是上面那个aabaaa那个next数组,到第二个a这失配了。此时a=1,则j要回到第一个位置取比呀,所以j=next[2],而此时next[2]的值是a也就是1,回溯到模式串第一个位置(存字符串的时候是从第一个位置存的),而你会发现第二个a的前面只有一个a,有0个公共最长前后缀,而假如aabaaa中第四个a失配了即j=5,他的最长公共前后缀是1,就是a,而next[5]=2,发现了没,一旦他失配,他所回溯的位置是最长公共前后缀长度+1,而按道理第一个a的next[1]的值为什么是0呢,而不是1,其实我感觉1也可以,但是源码就是next[1]=0;也可能是我理解错误,或者你可以直接理解为第一个位置前面肯定没有字符,所以为0,在求next数组的之后直接默认next[1]=0, next[2]=1 , 然后第三个位置开始存最长公共前后缀+1,所以aabaaa,第三个位置是b,则a和a最长公共前后缀为1,所以next[3]=2,以此类推,存完next数组,回溯的问题就差不多解决了,也就是代码里面的这里
kmp算法粗略理解(仅总结个人理解以便复习)_第2张图片
而如果匹配成功呢,则像上面说的i和j向后移,而这个j==0这个是怎么来的呢,我们想到next数组第一个位置的值是0,
当主串和模式串的第一个字符不匹配时,j就为0了,这时候再循环的时候,if语句成立,i++和j++的目的是让模式串的第一个字符和主串的下一个字符比较,而在这次循环中是没有字符比较的,反过来说如果你不把j等于0这个条件放在里面就会导致i和j无法后移,而此时是没有比较的,只是i和j向后面移动了而已,所以如果j等于0说明没有比较,所以减去它就可以了,如下代码

if(j==0)
    	sum--;

就得出了14这个结果。
本人对next数组的第一个和第二个位置的理解还不是很清楚,如果哪位大佬知道的话欢迎留言。

你可能感兴趣的:(kmp)