KMP算法

来源:互联网 发布:通过网络被骗的案例 编辑:程序博客网 时间:2024/06/08 14:50

KMP算法是D.E.Knuth、J.H.Morris和V.R.Pratt共同提出的,简称KMP算法。该算法较BF算法有较大改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。

字符串匹配最开始我们使用的是Brute-Force算法,又称简单匹配。其基本思路是:从目标串s=“s0s1…sn-1”的第一个字符开始和模式串t=“t0t1…tm-1”中的第一个字符比较,若相等,则继续逐个比较后续字符;否则从目标串s的第二个字符开始重新与模式串t的第一个字符进行比较。依次类推,若从模式串s的第个字符开始,每个字符依次和目标串t中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,函数返回-1。

但是这种算法很多时间都浪费在回溯——回溯后做了无效的匹配失败,所以要考虑匹配的效率,便是KMP算法。

以下是转自于 http://blog.csdn.net/u011564456/article/details/20862555个人认为对理解有所帮助。


假设在我们的匹配过程中出现了这一种情况:

根据 KMP 算法,在该失配位会调用该位的 next 数组的值!在这里有必要来说一下next 数组的作用!说的太繁琐怕你听不懂,让我用一句话来说明:

返回失配位之前的最长公共前后缀!

好,不管你懂不懂这句话,我下面的文字和图应该会让你懂这句话的意思以及作用的!

首先,我们取之前已经匹配的部分(即蓝色的那部分!)


我们在上面说到 next 数组的作用时,说到 “ 最长公共前后缀 ” ,体现到图中就是这个样子!


接下来,就是最重要的了!


没错,这个就是 next 数组的作用了 :

返回当前的最长公共前后缀长度,假设为 len 。因为数组是由 开始的,所以 next数组让第 len 位与主串匹配就是拿最长前缀之后的第 位与失配位重新匹配,避免匹配串从头开始!如下图所示!(重新匹配刚才的失配位!)

 

如果都说成这样你都不明白,那么你真的得重新理解什么是 KMP 算法了!

 

接下来最重要的,也是 KMP 算法的核心所在,就是 next 数组的求解!不过,在这里我找到了一个全新的理解方法!如果你懂的上面我写的的,那么下面的内容你只需稍微思考一下就行了!

 

跟刚才一样,我用一句话来阐述一下 next 数组的求解方法,其实也就是两个字:

继承

、当前面字符的前一个字符的对称程度为 的时候,只要将当前字符与子串第一个字符进行比较。这个很好理解啊,前面都是 ,说明都不对称了,如果多加了一个字符,要对称的话最多是当前的和第一个对称。比如 agcta 这个里面 的是 ,那么后面的 的对称程度只需要看它是不是等于第一个字符 了。

、按照这个推理,我们就可以总结一个规律,不仅前面是 呀,如果前面一个字符的 next 值是 ,那么我们就把当前字符与子串第二个字符进行比较,因为前面的是,说明前面的字符已经和第一个相等了,如果这个又与第二个相等了,说明对称程度就是 了。有两个字符对称了。比如上面 agctag ,倒数第二个  next  ,说明它和第一个 对称了,接着我们就把最后一个 与第二个 比较,又相等,自然对称成都就累加了,就是 了。  

、按照上面的推理,如果一直相等,就一直累加,可以一直推啊,推到这里应该一点难度都没有吧,如果你觉得有难度说明我写的太失败了。

当然不可能会那么顺利让我们一直对称下去,如果遇到下一个不相等了,那么说明不能继承前面的对称性了,这种情况只能说明没有那么多对称了,但是不能说明一点对称性都没有,所以遇到这种情况就要重新来考虑,这个也是难点所在。


如果蓝色的部分相同,则当前 next 数组的值为上一个 next 的值加一,如果不相同,就是我们下面要说的!

如果不相同,用一句话来说,就是:

从前面来找子前后缀

、如果要存在对称性,那么对称程度肯定比前面这个的对称程度小,所以要找个更小的对称,这个不用解释了吧,如果大那么就继承前面的对称性了。

2 、要找更小的对称,必然在对称内部还存在子对称,而且这个必须紧接着在子对称之后。

 

如果看不懂,那么看一下图吧!

 

个人get到的重点就是一个词——继承(对称性的继承)。

以下是代码实现:

1、求next数组

void GetNext(SqString t,int next[]) 

{  int j,k;

  j=0;k=-1;next[0]=-1;

   while(j<t.length-1)

   { if (k==-1 || t.data[j]==t.data[k])

   {   j++;k++;

       next[j]=k;

   }

   elsek=next[k];

   }

}

2、KMP算法

intKMPIndex(SqString s,SqString t)

{  int next[MaxSize],i=0,j=0;

   GetNext(t,next);

   while (i<s.length &&j<t.length)

   {  if(j==-1 || s.data[i]==t.data[j])

     { i++;

       j++;             //i,j各增1

     }

     else j=next[j];       //i不变,j后退

   }

   if (j>=t.length)

     return(i-t.length); //返回匹配模式串的首字符下标

   else

     return(-1);             //返回不匹配标志

}

 

 

PS:听说还有升级版……,到时候再看看。

0 0
原创粉丝点击