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网浙江大学数据结构课程视频讲义

原文地址:https://www.cnblogs.com/wanghao-boke/p/12078121.html