关于KMP匹配模式算法的小结

关于串的匹配模式算法有两种:

1.朴素模式匹配算法(也称为暴力破解算法)

2.KMP模式匹配算法(有未优化版的和优化版两种)

下面开始介绍两种模式匹配算法:

在串的模式匹配中,例如主串abcdabef中找子串abe,我们能想到的最简单的算法就是利用两个变量i和j,加上两个嵌套的for循环,i用于指定主串字符,j用于指定子串字符例如

for(i=0;i<=m-1;i++)  //m为主串的长度

    for(j=0;j<=n-1;j++) //n为子串的长度

        execute statement //匹配后的执行语句

这种可以称为在数学上叫循环式枚举法来进行全比较的模式匹配算法,也就是我们所说的朴素模式匹配算法。

该算法满足解决问题的算法定义要求,但该算法却有着比较复杂的时间复杂度O(m*n),但是经过研究我们可以发现,这个算法其实是可以优化的,而这个优化后的算法就是KMP模式匹配算法。

KMP模式匹配算法中的KMP是三个人名中的英文字母开头,KMP的算法思想是在i++ j++上做优化,也就是对i和j的定位做出优化,减少可预见的无效的i++ j++定位次数,从而减少算法的时间复杂度达到一个优化的效果。那么KMP算法是如何来进行i j的从新定位的呢?

当在每次匹配失败时i的值保持不变,j根据一个next(j)函数来取值。getnext(j)是一个根据j值变化定义的数组,求的是在模式串位置j处前面的最大相同前后缀长度,并且next数组的长度就是模式串的长度。下面是getnext()的推导方法:

在推导之前我们必须要先了解一下什么是一个字符串的真前缀和真后缀,以ABACABA为例,其相同前后缀有A和ABA,最大相同前后缀就是ABA长度为3。那么如何去确定在模式串中每个位置所对应的最大相同前后缀的值呢?

首先了解一下next的函数定义:

next()实现函数的代码如下:

void getnext(string T,int *next){

      int i,j;

      i=1;

      j=0;

     next[1]=0;

     while(i

         if(j==0 || T[i]==T[j])  //T[i]表示后缀的单个字符 T[j]表示前缀的单个字符

              {

               ++i;++j; 

               next[i]=j; //字符相同的话就自增,寻找下一个相同的值,并且把j的值赋给next[i]

               }

         else

               j=next[j];//若字符不相同则j值回溯

              }

}

该段代码计算出当前要匹配串T的next[i]数组,此时就可以描述KMP模式匹配算法了,在朴素模式匹配算法的基础上,当两个字符不相等时,对i 和j的处理由原来的i++和j++改写为i不变且j根据next数组来确定j的值。

KMP模式匹配算法的改进:

当next数组在进行前缀字符与后缀字符进行比较的时候,如果前缀字符与后缀字符相同,这个时候就可以把前缀字符位置的next[]值赋值给后缀字符位置的next[]值,就不需要重复计算。

关于KMP匹配模式算法的小结_第1张图片

关于KMP匹配模式算法的小结_第2张图片

 

你可能感兴趣的:(关于KMP匹配模式算法的小结)