• 字符串的模式匹配


    问题描述:如果子串T在主串中存在,则返回存在的位置,如果不存在,则返回-1。

    1.基本方法

     从主串的第pos位置字符开始和模式子串字符比较,如果相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式子串的字符比较。直到找到匹配字符串或者是主串结尾。

    伪代码如下:

    Index(T,S,pos)
        i <- pos
        j <- 1
      while i<=length[T] and j<=length[S] 
            if T[i]=S[j]
                  i++
                  j++
            else 
                  i <- i-j+2
                  j <- 1
       if j> length[S] 
         return i-lenght[S]
        else 
        return -1;

    例如,主串T为:ababcabababab,子串为ababa,上述过程如下图所示。

     源代码如下:

    /*
    检测从主串T的pos位置开始,是否有和子串S匹配,如果有返回匹配开始位置,如果没有,返回-1
    T:主串
    S:子串
    tlength:主串长度
    slength:子串长度
    pos:主串开始位置
    */
    int Index (char T[],char S[],int tlength,int slength,int pos)
    {
        int j=0,i=pos;
        while(i<tlength&&j<slength)
        {
            if(T[i]==S[j])
            {
                i++;
                j++;
            }
            else
            {
                i=i-j+1;
                j=0;
            }
        }
        return j==slength?i-slength:-1;
    
    }

     运行结果如下:

    完成源代码见文章最后!

    2.KMP算法

         由上述基本方法匹配过程中,很多次的比较都没有意义的,比如当第一个主串的c与子串中的a不匹配时,下一次的 主串的b和子串的a(第一个)的比较可以通过分析子串的特点直接跳过这次比较。KMP算法就是为了告诉我们,我们应该每当一趟匹配过程中出现比较不等时,我们不需要回溯i指针。而是利用已经得到的“部分匹配”的结果将模式子串想右“滑动”尽可能远的距离,然后继续比较。那么我们应该如何确定这个尽可能远的距离哪?

         我们通过分析子串P1P2..Pm的特点,可以得出这个“尽可能远的距离的计算方法”。

         我们假设主串S1S2...Sn和子串P1P2...Pm在主串i和主串j位置不匹配,我们假设我们希望下次子串k(k<j)位置与主串i位置进行比较,即

              P1P2...Pk-1=Si-k+1...Si-1

         由于在匹配过程中主串中的第i和子串中的第j和不相等,也就是说子串位置j前面的所有都匹配了,即:

                      Pj-K+1...Pj-1=Si-k+1...Si-1

          由上面两个等式的:

                     P1P2...Pk-1=Pj-K+1...Pj-1

         也就是说,要想在当不匹配时,子串向右滑动最远距离,只要找到子串中满足上式的最大k值即可,

       我们用next[j]表示当模式子串中第j个字符与主串中相应的字符“失配”时,在模式中需要重新和主串中该字符比较的字符的位置。

       

    在求得next后,匹配过程进行如下:

    假设以指针i和j分别指示主串和模式子串中正待比较的字符,令i的初值为pos,j的初值为0.若在匹配过程中Si=Pj,则i和j分别加1,否则,i不变,而j退到next[j]的位置再比较,若相等,则指针各增1,否则,j再退到下一个next值的位置,依次类推,直到下面两种可能:一种是j退到某个next值的字符比较相等,则指针各自增1,继续进行匹配;另一种是j退到0(即模式的第一个字符失配),则此时需要将模式继续向右滑动一个位置,即从主串的下一个字符Si+1起和模式重新开始匹配。

    举例说明:

    例如,主串T为:acabaabaabcacaabc,子串为abaabcac,上述过程如下图所示。

    首先计算出zi串next[]={0,1,1,2,2,3,1,2},匹配过程如下:

    实现程序如下:

    int KMP_Index(char T[],char S[],int tlength,int slength,int pos)
    {
        int *next=(int*)malloc(slength*sizeof(int));
        KMP_Next(S,next,slength);
    
        int j=-1,i=pos-1;
        while(i<tlength&&j<slength)
        {
            if(j==-1||T[i]==S[j])
            {
                i++;
                j++;
            }
            else
                j=next[j];
        }
        return j==slength?i-slength:-1;
    
    
    }

     程序源代码实现:StringPatternMatching.zip

  • 相关阅读:
    【SQLServer】 查询一个字段里不同值的最新一条记录
    【MySQL】mysql5.7数据库的安装和配置
    【Java】JDK安装及环境变量配置
    【Oracle】SQL语句优化
    【JavaScript】 控制自适应高度
    【Java】登录验证码
    【JavaScript】 直接下载保存文件
    【Java】Java批量文件打包下载zip
    【Java】Java 单文件下载及重命名
    主机在无线网络的情况下,设置centos7.2虚拟机网络联通
  • 原文地址:https://www.cnblogs.com/lufangtao/p/3245647.html
Copyright © 2020-2023  润新知