KMP算法最详细分析!!

1.首先明确,next数组存在的意义是什么:

示例如下:

主串:  a b a b c a b c a c b a b

模式串: a b c a c

匹配过程如下:

第一次匹配:

这个时候,如果不用KMP,而是用BF,那么我们的做法很明显:

尝试模式串的第一个字符和主串的第二个字符进行匹配。

很明显,这是多余的,这是肯定不成立的,而next数组直接告诉我们,跳过这一步,直接如下

这就是next的作用,如果还不明显,你再看上图,模式串的第五位是c和主串相对位置的b不匹配,那么按照BF算法,我们需要

再用主串的第四位和模式串的第一位比较,但是,很舒服,next数组告诉我们不用这样,直接如下

以上就是next的作用,跳过无用的匹配。

2.思考,next为什么可以这样做呢?

首先,什么是next数组:

上述模式串的next数组如下:

a b c a c

0 1 1 1 2

简而言之,每个字母x对应的next数组值是这样的出来的:x前的子串和主串的前几个字母相同,则只需要比较x和主串的第y个元素就好了,那么这个y就是next[x的索引]的值。

下面引入求next数组的算法:

next存储起始从1开始

void GetNext(string s,int next[])//s是模式串

{

    int i=1,j=0;next[1]=0;

    while(i<s.length()-1){

        if(j==0||s[i]==s[j]){

            i++;j++;

            next[i]=j;

        }

        else{

            j=next[j];//这一步很关键,他起到的作用就是刚才上面讲到的配对失败之后,直接跳到指定的位置

        }

    }

}

既然已经得到next数组了,那么实际操作就很简单了,附上KMP代码:

int KMP(string s,string t,int pos)//参数分别是主串,模式串,求模式串在主串第pos个字符之后的位置

{

    int i=pos,j=1;

    while(i<s.length()&&j<t.length()){

        if(j==0||s.data[i]==t.data[j]){

            i++;j++;//均后移一位

        }

        else j=next[j];//找到适当的位置

    }

    if(j>t.length())return i-t.length();//匹配成功

    else return -1;

}

猜你喜欢

转载自blog.csdn.net/qq_41076797/article/details/82840672