• KMP算法


    KMP算法是字符串匹配功能的一个优化。

    所谓字符串匹配的问题意思是说,给一个字符串和一个匹配串,判断这个匹配串是否被这个字符串包含。或者说求匹配字符串在给的字符串中出现的位置。

    在C语言中,strstr函数就是这个字符串功能的实现,既然你看到了这篇博客,我就默认你已经了解strstr函数。

    举个例子:

    给一个字符串 string:abcabcabcabcacabxy 求字符串pattern:abcabcacab在string中字符串的位置。

    如果按照暴力算法,就是一个一比对过去:

    暴力破解的思路就是字符串和匹配串一路比过去,若相等,就一起往后移一位,但是如果不相等,匹配串就要回到起点,字符串回到开始匹配位置的下一个字符串。

    /*
    match.cpp
    */
    #include<cstdio>
    #include<cstring>
    
    int main()
    {
        char *string = "abcabcabcabcacabxy";
        char *pattern = "abcabcacab";
    
        int len_string = strlen(string);
        int len_pattern = strlen(pattern);
    
        int i = 0;
        int j = 0;
        int mark_i = 1;
        bool flag = false;
        while(i < len_string && j < len_pattern)
        {
            while (string[i] == pattern[j])
            {
                i++;
                j++;
            }
            if (j == len_pattern)
            {
                flag = true;
                break;
            }
            if (i == len_string || len_string - mark_i < len_pattern)
            {
                break;
            }
            
            j = 0;
            i = mark_i;
            mark_i++;        
        }
    
        if (flag == true)
        {
            printf("The [%s] is in [%s]
    ", pattern, string);
        }
        else
        {
            printf("The [%s] is NOT in [%s]
    ", pattern, string);        
        }
    
        return 0;
        
    }

    上面的代码我还加了点优化方案在里,比如说字符串剩下的长度小于匹配串的长度,那么直接退出,返回false了。

    暴力破解的时间复杂度都是O(m*n),其中m是字符串的长度,n是匹配串的长度。如果m和n都不大还好,一旦两个都是1000以上了,计算时间就很长了。

    其中KMP算法就是优化字符串匹配方法的其中一种优化程度较好的算法。

    KMP算法是这个算法建立的三个人Knuth、Morris、Pratt的首字母缩写。

    它的思路就是对匹配串进行一定的算法处理,减少重新比对的次数。

    对匹配字符串的处理方法就是对它建立一个match数组,来表示以当前字符为结束的子串中是否有相同的真字符串。其中,建立的公式为:

    具体求KMP match数组计算过程如下:

    具体的算法实现:

     
    void BuildMatch( char *pattern, int *match )
    {
        Position i, j;
        int m = strlen(pattern);
        match[0] = -1;
          
        for ( j=1; j<m; j++ ) {
            i = match[j-1];
            while ( (i>=0) && (pattern[i+1]!=pattern[j]) )
                i = match[i];
            if ( pattern[i+1]==pattern[j] )
                 match[j] = i+1;
            else match[j] = -1;
        }
    }
      
    Position KMP( char *string, char *pattern )
    {
        int n = strlen(string);
        int m = strlen(pattern);
        Position s, p, *match;
          
        if ( n < m ) return NotFound;
        match = (Position *)malloc(sizeof(Position) * m);
        BuildMatch(pattern, match);
        s = p = 0;
        while ( s<n && p<m ) {
            if ( string[s]==pattern[p] ) {
                s++; p++;
            }
            else if (p>0) p = match[p-1]+1;
            else s++;
        }
        return ( p==m )? (s-m) : NotFound;
    }

    练习题:
    https://www.cnblogs.com/wanghao-boke/p/12006005.html

    参考:中国mooc网浙江大学数据结构课程视频讲义

  • 相关阅读:
    zookeeper笔记整理(二)
    zookeeper笔记整理(一)
    SpringBoot源码分析(三)整合MyBatis
    四、MyBatis终结篇(补充中...)
    三、SpringMVC终结篇(补充中...)
    二、SpringAOP终结篇(补充中...)
    一、SpringIOC终结篇(补充中...)
    跳出初学MySQL知识的原理整理(一)
    SpringBoot源码分析(二)启动原理
    一文带你学会基于SpringAop实现操作日志的记录
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/12078121.html
Copyright © 2020-2023  润新知