串的模式匹配算法

    首先,关于串的模式匹配经典的算法:

                 即设两指针,分别指向主串和模式串,每次对以主串指针为首的元素进行匹配

(示例算法实现)

    int index(SString S,SString T,int pos)

  {//返回子串T在主串中第pos个字符之后的位置,元素T[0]与S[0]存放串长

   i=pos;    j=1;

    while(i<=S[0]&&j<=T[0])

         {

           if(S[i]==T[j]){++i;  ++j;}//继续比较

           else {i=i-j+2;j=1;}//指针回溯

         }

if(j>T[0])return i-T[0];

else return 0;

  }

(若主串长n,模式串长m,则该算法时间复杂度为O(n*m))    

上面便是关于模式串的经典算法,思路实现比较简单,但也是关于串匹配的主要思想,许多串的操作核心源于此。

    然而,上面算法的主串指针经常需要回溯,效率较低,且难用于文件流扫描匹配。由此,我们希望不用回溯

主串指针的算法。由于在经典算法中,当主串指针需要回溯时,其前面的元素已经与模式串比较过,因此,我们

需要另一数组来告知我们当前元素位置前面匹配情况,以便我们在当前主串位置不匹配时不用回溯指针而得到重

新与之匹配的模式串中的元素位置.即所谓的KMP算法

算法示例:

   int index_kmp(SString S,SString T,int pos)

    {

     i=pos;  j=1;

      while(i<=S[0]&&j<=T[0])

        {

          if(j==0||S[i]==T[j]){++i;++j;}

          else j=next[j];

       } 

         if(j<T[0])return i-T[0];

         else return 0;

    }

与经典算法比较可以发现,算法大体一致,区别在于不回溯并继续比较模式串的合适位置即next[];

接下来是关于如何求next[]数组的问题

这个问题也可以想象成主串和模式串是本身,指针前一部分是模式串,后一部分是主串,匹配有两种

情况即移动到下一元素和重新比较

算法示例:

  void  get_next(SString T,int next[])

           {

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

            whiel(i<T[0])

                 {

                   if(j==0||T[i]==T[j]){++i;++j;next[i]=j;}

                   else j=next[j];

                 }

           }

由上可知,next[]数组的值由其前面的元素确定,但事实上,当按上面算法求的next的数组中,当串的

位置元素与其next数组位置元素一致时,比较变得无意义,因此对上面算法进行改进,加入当前元素的

影响

算法示例:

  void  get_nextval(SString T,int nextval[])

      {

       i=1;nextval[1]=0;j=0;

       while(i<T[0])

             {

               if(j==0||T[i]==T[j])

                      {

                       ++i;++j;

                      if(T[i]!=T[j])nextval[i]=j;//加入自身值的影响

                      else nextval[i]=nextval[j];

                      }

             else j=nextval[j];

             }

      }

比较以上算法可以发现其大体原理一样,由于现实概率问题,经典算法在实际执行时时间类似于O(n+m),

因此仍有很高的效率。

posted @ 2013-04-25 00:19  不死猿  阅读(489)  评论(0)    收藏  举报