zoukankan      html  css  js  c++  java
  • KMP算法

    KMP字符串匹配算法

     算法流程

    (1)

      首先,主串"BBC ABCDAB ABCDABCDABDE"的第一个字符与模式串"ABCDABD"的第一个字符,进行比较。因为 B 与 A 不匹配,所以模式串后移一位。

    (2)

      因为 B 与 A 又不匹配,模式串再往后移。

    (3)

      就这样,直到主串有一个字符,与模式串的第一个字符相同为止。

    (4)

      接着比较主串和模式串的下一个字符,还是相同。

    (5)

      直到主串有一个字符,与模式串对应的字符不相同为止。

    (6)

      这时,最自然的反应是,将模式串整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。

    (7)

      一个基本事实是,当空格与 D 不匹配时,你其实是已经知道前面六个字符是"ABCDAB"。KMP 算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,而是继续把它向后移,这样就提高了效率。

    (8)

              

    (9)怎么做到这一点呢?可以针对模式串,设置一个跳转数组int next[],这个数组是怎么计算出来的,后面再介绍,这里只要会用就可以了。

      已知空格与 D 不匹配时,前面六个字符"ABCDAB"是匹配的。根据跳转数组可知,不匹配处 D 的 next 值为 2,因此接下来从模式串下标为 2 的位置开始匹配。

    (10)

      因为空格与 C 不匹配,C 处的 next 值为 0,因此接下来模式串从下标为 0 处开始匹配。

    (11)

      因为空格与 A 不匹配,此处 next 值为 -1,表示模式串的第一个字符就不匹配,那么直接往后移一位。

    (12)

      逐位比较,直到发现 C 与 D 不匹配。于是,下一步从下标为 2 的地方开始匹配。

    (13)

      逐位比较,直到模式串的最后一位,发现完全匹配,于是搜索完成。

    next 数组是如何求出的

      next 数组的求解基于“真前缀”和“真后缀”,即next[i]等于P[0]...P[i - 1]最长的相同真前后缀的长度。

        

    1. i = 0,对于模式串的首字符,我们统一为next[0] = -1
    2. i = 1,前面的字符串为A,其最长相同真前后缀长度为 0,即next[1] = 0
    3. i = 2,前面的字符串为AB,其最长相同真前后缀长度为 0,即next[2] = 0
    4. i = 3,前面的字符串为ABC,其最长相同真前后缀长度为 0,即next[3] = 0
    5. i = 4,前面的字符串为ABCD,其最长相同真前后缀长度为 0,即next[4] = 0
    6. i = 5,前面的字符串为ABCDA,其最长相同真前后缀为A,即next[5] = 1
    7. i = 6,前面的字符串为ABCDAB,其最长相同真前后缀为AB,即next[6] = 2
    8. i = 7,前面的字符串为ABCDABD,其最长相同真前后缀长度为 0,即next[7] = 0

     

     

    计算next数组:(顺序表的形式)

      

    /* P 为模式串,下标从 0 开始 */
    void GetNext(string P, int next[])
    {
        int p_len = P.size();
        int i = 0;   // P 的下标
        int j = -1;  
        next[0] = -1;
        while (i < p_len)
        {
            if (j == -1 || P[i] == P[j])
            {
                i++;
                j++;
                next[i] = j;
            }
            else
                j = next[j];
        }
    }

    计算next数组:(链表的形式)

    //next数组的计算
    
    void makeNext(PStrString p,int *next){
        int i= 0,k=-1;
        next[0]=-1;//初始化
        while (i<p->n-1)
        {
            while (k>=0&&p->c[i]!=p->c[k])
            {
                k=next[k];
            }
            i++,k++;
            next[i]=k;
        }
    }

     

    KMP(顺序表形式)

    int KMP(string S, string P, int next[])
    {
        GetNext(P, next);
    
        int i = 0;  // S 的下标
        int j = 0;  // P 的下标
        int s_len = S.size();
        int p_len = P.size();
    
        while (i < s_len && j < p_len) // 因为末尾 '' 的存在,所以不会越界
        {
            if (j == -1 || S[i] == P[j])  // P 的第一个字符不匹配或 S[i] == P[j]
            {
                i++;
                j++;
            }
            else
                j = next[j];  // 当前字符匹配失败,进行跳转
        }
    
        if (j == p_len)  // 匹配成功
            return i - j;
        
        return -1;
    }

     

    KMP (链表形式)

    int pMath(PSeqString t,PSeqString p,int *next){
        int i,j;
        i =0;j=0;
        while (i<p->n&&j<t->n)
        {
            if(i==-1||p->c[i]==t->c[j]){
                i++;
                j++;
            }else
            {
                i=next[i];
            }
            
        }
        if (i>=p->n)
        {
            return j-p->n+1;
        }else
        {
            return 0;
        }
    }

     

    因上求缘,果上努力~~~~ 作者:每天卷学习,转载请注明原文链接:https://www.cnblogs.com/BlairGrowing/p/13034930.html

  • 相关阅读:
    hdu 2089 不要62(数位dp)
    hdu 3555 Bomb(数位dp)
    hdu 4544 湫湫系列故事——消灭兔子(优先队列)
    STL Algorithms 之 unique
    hdu 1075 What Are You Talking About(map)
    hdu 4268 Alice and Bob(贪心+multiset)
    hdu 4302 Holedox Eating(优先队列/线段树)
    9-16Jenkins-4节点
    9-16Jenkins-3可用的环境变量、参数化构建和依赖
    9-16Jenkins-2定时任务
  • 原文地址:https://www.cnblogs.com/BlairGrowing/p/13034930.html
Copyright © 2011-2022 走看看