zoukankan      html  css  js  c++  java
  • 计算机基础数据结构讲解第十二篇-字符串模式匹配KMP算法第二讲

      现在继续讲解KMP算法的有关知识,以及KMP算法的代码和改进,改进用nextval[]数组。

    一:next公式讲解

      由公式可知next[1]=0,也就是模式串第一个字符(j=1),与主串第i个字符发生失配时,规定next[1]=0,将模式串右移一位,然后模式串第一个字符和主串的下一个位置(i+1)进行比较。
      设next[j]=k,那此时next[j+1]等于多少呢?可能有两种情况:

    1.Pk=Pj

      若Pk=Pj,则说明有最大公共前后缀,此时next[j+1]=k+1,即next[j+1]=next[j]+1。

    2.Pk≠Pj

      若Pk≠Pj,则说明找到的最大公共前后缀不符合,这时可以把求next函数值的问题视为一个模式匹配的问题,如果不匹配,需要找到长度更短的相等前后缀,依次类推则一直向后寻找,寻找更小的k为k',则next[j+1]=k'+1。也可能不存在任何k'满足上诉条件,即不存在长度更短的相等前缀后缀,令next[j+1]=1。
      关于知道next[j]的值,计算next[j+1]的值这里已经介绍了,下面就来介绍求next值的程序。

    二:求next程序

      算法如下:

    void get_next(String T,int next[]){
      int i=1;j=0;
      next[1] = 0;
      while(i<T.length){
        if(j==0!!T.ch[i]=T.ch[j]){
          ++i;++j;
          next[i] = j;  //Pi=Pj
        }
        else
          j=next[j];  //否则令j=next[j],循环继续
      }
    }
    

      用手工的方法计算的时候,比较困难,所以还是用之前的方法求next数组。而KMP算法就比较简单了,根据之前得到的过程代码如下:

    int Index_KMP(String S,String T,int next[]){
      int i = 1;j = 1;
      while(i<=S.length&&j<=T.length){
        if(j==0||S.ch[i]=S.ch[j]){
          ++i;++j //没有公共前后缀或子串第一个字符比较,直接比较i+1位
        }
        else
          j=next[j];  //模式串向右移动
      }
      if(j>T.length)
        return i = T.length;  //匹配成功
      else
        return 0;
      }
    

      由上面的推断可知,KMP算法的时间复杂度是O(n+m),但在一般情况下,普通模式匹配的实际执行时间近似为O(n+m),因此至今仍被采用。KMP算法仅在主串与子串有很多部分匹配,即最长公共前后缀时才显得比普通算法快得多,其主要优点是主串不回溯。

    三:KMP算法的进一步优化

      前面定义的next数组在某些情况下尚有缺陷,还可以进一步优化。当Pj≠Sj,下次匹配应该是P(next[j])跟Sj比较,如果Pj=P(next[j]),那么相当于拿一个和Pj相等的字符跟Sj比较,这必将导致继续失配,这样的比较毫无意义。
      那么如何进行处理呢?就可以继续递归,将next[j]修正为next[next[j]],直至两者不相等为止,更新后的数组命名为nextval。计算next数组修正值的算法如下,匹配算法不变,只需要修改一部分。代码如下:

    void get_nextval(String T,int nextval[]){
      int i=1;j=0;
      nextval[1] = 0;
      while(i<T.length){
        if(j==0!!T.ch[i]=T.ch[j]){
          ++i;++j;
          if(T.ch[i]!=T.ch[j])
            nextval[i] = j
          else
            nextval[i] = nextval[j];
        }
        else
          j=next[j];
      }
    }
    
  • 相关阅读:
    python面向对象三大特性之一封装
    python面向对象的三大特性之一多态
    python之子类调用父类的两种方式
    python之接口继承
    python之组合与继承的使用场景
    Learning to Rank Short Text Pairs with Convolutional Deep Neural Networks(paper)
    lesson9-小象学院cv
    tips
    C5-fasterrcnn-小象cv-code
    C4-ResNet-TF-小象cv-code
  • 原文地址:https://www.cnblogs.com/ITXiaoAng/p/13737327.html
Copyright © 2011-2022 走看看