kmp算法(下)——next数组

接上一篇。

 

4、如何计算next数组

       对于给定的字符串p,其next数组的含义是:对于k=next[j]p的前缀p[0…k-1]p的后缀p[j-k…j-1]匹配,k要尽可能的大,且k<j.我们可以根据上述含义写出next的brute force计算代码。复杂度应该是O(n2)。

 

换个思路,现在next[0]=-1,next[1]=0.

假设k=next[j],则p[0…k-1]=p[j-k…j-1],那么求next[j+1]有两种情况:

1)如果p[k]=p[j],则p[0…k]=p[j-k…j],所以next[j+1]=k+1=next[j]+1;

2)如果p[k]!=p[j],这是可以看做另外一个字符串匹配的问题,主串和模式串都是p,当匹配失败时,k应该如何移动呢?显然是k=next[k]。请仔细琢磨这段话。【参考《数据结构-严蔚敏》p82-83】

仿照kmp算法,可以得到next数组的求法:


voidgetNext(const char *p,int *next)
{
    int i,j;
    next[0]=-1;
    i=0;
    j=-1;
    while(i<(signed)strlen(p)-1)
    {
        if(j==-1||p[i]==p[j])    //匹配的情况下,p[j]==p[k]
        {
            i++;
            j++;
            next[i]=j;
        }
        else                   //p[j]!=p[k]
            j=next[j];
    }
}

 

       next数组是kmp算法的核心,只有真正理解next数组,才能熟练掌握kmp算法。

 

       复杂度分析:getNext()函数的复杂度是O(m),通常情况下模式串长度m<<主串长度n,因此增加的时间是值得的。由于使用了辅助数组,因此空间复杂度是O(m)。

 

       虽然朴素字符串匹配算法的复杂度是O(n*m),但是在一般情况下实际的执行时间接近O(n+m)。KMP算法仅当模式串与主串之间存在许多“部分匹配”的情况下(这时才会有大量的回退)才显得比朴素匹配算法快得多。KMP算法的最大优点是不需要回溯指针,对主串仅需要从头至尾扫描一遍,对于外设输入庞大的文件很有效,可以边读入遍匹配,无需回头重读。



 5、优化

其实上面的getNext()还可以优化:

voidgetNext(const char *p,int *next)

{

    int i,j;

    next[0]=-1;

    i=0;

    j=-1;

    while(i<(signed)strlen(p)-1)

    {

        if(j==-1||p[i]==p[j])    //匹配的情况下,p[j]==p[k]

        {

            i++;

            j++;

            if(p[i]!=p[j])      next[i]=j;

            else                 next[i]=next[j];///p[i]=p[j]时优化

        }

        else                   //p[j]!=p[k]

            j=next[j];

    }

}

这时匹配算法不变。


       后记:kmp算法是D.E.Knuth与J.H.Morris与V.R.Pratt同时发现的字符串匹配的改良算法。也是我单个看的最久的算法。

在网上看很多blog,包括比较有名的matrix67,July等,但是我都没看太明白。尤其是July的,一大堆,前面的朴素算法都弄了一堆图,非常详细,这点很好。可是后面求next数组时,一会弄个下标从0开始的,一会弄个下标从1开始的,让新手无所适从。本来就是不懂才看,结果看完更郁闷了。最后还是看了严蔚敏老师的《数据结构》上的,才似乎懂了些。那本书上是下标从1开始的,我感觉讲的比网上的blog要详细的多,易懂的多。这本书之前大二时学习时没看太细,虽然考试分数挺高,但是显然书上好多内容都没有掌握。现在还在看。这里附上这本书的pdf连接,可以直接下载


原创文章,转载请注明出处:http://blog.csdn.net/fastsort/article/details/9971953



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值