http://blog.youkuaiyun.com/myjoying/article/details/7947119
KMP算法是一种高效的模式匹配算法。
与BF算法的比较
在普通的匹配算法BF中,目标串和模式串的索引值都需要重新回到起点再次进行匹配,所以该算法的时间复杂度较高,达到O(m*n)。KMP算法的核心思想是寻找模式串本身的特征,在此基础上达到目标串不回溯,模式串有规律回溯的目的,以减少回溯比较的次数,降低时间复杂度,达到O(m+n)。但是这是建立在提高空间复杂度的基础上的。
BF算法:时间复杂度O(m*n);空间复杂度O(1)
KMP算法:时间复杂度O(m+n);空间复杂度O(n)
KMP算法核心
KMP算法的核心是寻找模式串本身的规律。在该算法中表现为反映该规律的next数组。next数组的作用是在每次失配时,模式串根据next数组对应位置上的值回溯模式串索引的位置。next数组的求法也是KMP算法的精华所在。在本文的参考博文[1]和参考博文[2]中均给出了next数组的具体求法,但是遗憾的是在[1]中,并没有给出next数组的具体含义,而[2]中给出了具体的next定义。
next数组有如下定义:
(1) next[j]=-1 j=0
(2) next[j]=max ( k ): 0<k<j P[0...k-1]=P[j-k,j-1]
(3) next[j]=0 其他
该定义的意义就是next数组的首位均为-1。在其他位置上,该位置之前的子串中最长的相同前后缀长度(注释1)。当没有任何相同的前后缀的情况下,next值为0。
注释1:前后缀的含义,例如在a b c a b中,前缀和后缀均为"ab"。
next数组的计算方法
由next数组的定义可知,可以用一种递推的思想来求解next数组。
根据定义next[0] = -1
假设next[j] = k, 即P[0...k-1] == P[j-k,j-1]
(1)若P[j] == P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;
(2)若P[j] != P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。
代码实现:
求next数组
- void get_next(const char* ptrn,int* nextval)
- {
- int plen = strlen(ptrn);
- int i = 0;
- int k = -1;
- nextval[i] = -1;
- while(i < plen -1)
- {
- if (k == -1 || ptrn[i] == ptrn[k])
- {
- ++i;
- ++k;
- nextval[i] = k;
- }
- else
- {
- k = nextval[k];
- }
- }
- }
KMP算法
- int KMP_search(const char* src, const char* ptrn, const int *nextval )
- {
- int i=0;
- int j=0;
- int slen = strlen(src);
- int plen = strlen(ptrn);
- while(i<slen && j<plen)
- {
- if (j == -1 || src[i] == ptrn[j])
- {
- i++;
- j++;
- }
- else
- {
- j = nextval[j];
- }
- }
- if ( j >= plen)
- {
- return i - plen;
- }
- else
- {
- return -1;
- }
- }
参考博客[1]:http://blog.youkuaiyun.com/v_july_v/article/details/7041827
参考博客[2]:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html