• Algorithm --> KMP算法


    KMP算法

    一、传统字符串匹配算法

    /* 
     * 从s中第sIndex位置开始匹配p
     * 若匹配成功,返回s中模式串p的起始index
     * 若匹配失败,返回-1
     */
    int index(const std::string &s, const std::string &p, const int sIndex = 0)
    {
        int i = sIndex, j = 0;
    
        if (s.length() < 1 || p.length() < 1 || sIndex < 0)
        {
            return -1;
        }
    
        while (i != s.length() && j != p.length())
        {
            if (s[i] == p[j])
            {
                ++i;
                ++j;
            }
            else
            {
                i = i - j + 1;
                j = 0;
            }
        }
        return j == p.length() ? i - j: -1;
    }

    另外一种简单匹配:

    int Index_BF ( char S [ ], char T [ ], int pos )
    {
      /* 若串 S 中从第pos(S 的下标0≤pos<StrLength(S))个字符
      起存在和串 T 相同的子串,则称匹配成功,返回第一个
      这样的子串在串 S 中的下标,否则返回 -1    */
    
      int i = pos, j = 0;
      while ( S[i+j] != ''&& T[j] != '')
      {
        
    if ( S[i+j] == T[j] )       j++; // 继续比较后一字符     else     {       i ++;
          j = 0; // 重新开始新的一轮匹配     }  
      }

      if ( T[j] == '')      return i; // 匹配成功 返回下标   else      return -1; // 串S中(第pos个字符起)不存在和串T相同的子串 } // Index_BF

    二、KMP算法

    //http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

    定义

    1next[0]= -1  意义:任何串的第一个字符的模式值规定为-1

    2next[j]= -1   意义:模式串T中下标为j的字符,如果与首字符相同,且j的前面的1—k个字符与开头的1—k个字符不等(或者相等但T[k]==T[j])(1k<j)。

       如:T=”abCabCad” next[6]=-1,因T[3]=T[6]

    3next[j]=k    意义:模式串T中下标为j的字符,如果j的前面k个字符与开头的k个字符相等,且T[j] != T[k] 1k<j)。

             T[0]T[1]T[2]。。。T[k-1]==T[j-k]T[j-k+1]T[j-k+2]…T[j-1]  T[j] != T[k].1k<j;

     ( 4 ) next[j]=0   意义:除(1)(2)(3)的其他情况。

     

    举例

    01)求T=abcac”的模式函数的值。

         next[0]= -1  根据(1)

         next[1]=0   根据 (4)   因(3)有1<=k<j;不能说,j=1,T[j-1]==T[0]

         next[2]=0   根据 (4)   因(3)有1<=k<j;T[0]=a!=T[1]=b

         next[3]= -1  根据 (2)

         next[4]=1   根据 (3)  T[0]=T[3] T[1]=T[4]

           

    下标

    0

    1

    2

    3

    4

    T

    a

    b

    c

    a

    c

    next

    -1

    0

    0

    -1

    1

    T=abcab”将是这样:

    下标

    0

    1

    2

    3

    4

    T

    a

    b

    c

    a

    b

    next

    -1

    0

    0

    -1

    0

    为什么T[0]==T[3],还会有next[4]=0, 因为T[1]==T[4], 根据 (3)” T[j] != T[k]”被划入(4)。

    02)来个复杂点的,求T=”ababcaabc” 的模式函数的值。

      next[0]= -1    根据(1

            next[1]=0    根据(4)

            next[2]=-1   根据 (2)

      next[3]=0   根据 (3) T[0]=T[2] T[1]=T[3] 被划入(4

      next[4]=2   根据 (3) T[0]T[1]=T[2]T[3] T[2] !=T[4]

      next[5]=-1  根据 (2) 

      next[6]=1   根据 (3) T[0]=T[5] T[1]!=T[6]

      next[7]=0   根据 (3) T[0]=T[6] T[1]=T[7] 被划入(4

      next[8]=2   根据 (3) T[0]T[1]=T[6]T[7] T[2] !=T[8]

     

    下标

    0

    1

    2

    3

    4

    5

    6

    7

    8

    T

    a

    b

    a

    b

    c

    a

    a

    b

    c

    next

    -1

    0

    -1

    0

    2

    -1

    1

    0

    2

    只要理解了next[3]=0,而不是=1next[6]=1,而不是= -1next[8]=2,而不是= 0,其他的好象都容易理解。

    03)   来个特殊的,求 T=”abCabCad” 的模式函数的值。

    下标

    0

    1

    2

    3

    4

    5

    6

    7

    T

    a

    b

    C

    a

    b

    C

    a

    d

    next

    -1

    0

    0

    -1

    0

    0

    -1

    4

    next[5]= 0  根据 (3) T[0]T[1]=T[3]T[4],T[2]==T[5]

    next[6]= -1  根据 (2) 虽前面有abC=abC,T[3]==T[6]

    next[7]=4   根据 (3) 前面有abCa=abCa, T[4]!=T[7]

    T[4]==T[7],即T=” adCadCad”,那么将是这样:next[7]=0, 而不是= 4,因为T[4]==T[7].

    下标

    0

    1

    2

    3

    4

    5

    6

    7

    T

    a

    d

    C

    a

    d

    C

    a

    d

    next

    -1

    0

    0

    -1

    0

    0

    -1

    0

    代码

    #include <iostream.h>
    #include <string.h>
    using namespace std;
    
    void getNext(char *p,int *next)
    {
        int j,k;
        next[0]=-1;
        j=0;
        k=-1;
        while(j<strlen(p)-1)
        {
            if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
            {
                j++;
                k++;
                next[j]=k;
            }
            else                   //p[j]!=p[k]
                k=next[k];
        }
    }
    
    int KMPMatch(char *s,char *p)
    {
        int next[100];
        int i,j;
        i=0;
        j=0;
        getNext(p,next);
        while(i<strlen(s))
        {
            if(j==-1||s[i]==p[j])
            {
                i++;
                j++;
            }
            else
            {
                j=next[j];       //消除了指针i的回溯
            }
            if(j==strlen(p))
                return i-strlen(p);
        }
        return -1;
    }
    
    int main()//abCabCad
    {
         char* text="bababCabCadcaabcaababcbaaaabaaacababcaabc";
         char* pattern="abCab";
       
         cout<< KMPMatch(text, pattern) << endl;
    
         return 0;
    }
  • 相关阅读:
    安装SQL sever2008时显示重新启动计算机规则失败,应该怎么解决?
    C#获取当前日期时间(转)
    使用JQUERY实现页面局部刷新
    Metal渲染:实现画面比例功能
    Metal渲染:实现旋转/翻转功能
    依赖注入浅析
    iOS 消息推送实现 APNS
    使用#pragma阻止一些warnings
    github 多帐户使用
    Swift 实现Bitmask Option(Enum)
  • 原文地址:https://www.cnblogs.com/jeakeven/p/4696424.html
Copyright © 2020-2023  润新知