KMP算法学习

本文深入探讨了KMP算法作为一种高效的模式匹配方法,与BF算法相比的优势与局限性。重点介绍了KMP算法的核心思想、next数组的求解方法及其在实际代码实现中的应用。通过对比BF算法的时间与空间复杂度,阐述了KMP算法在减少回溯比较次数、降低时间复杂度方面的改进。同时,详细解释了next数组的定义及其在模式匹配过程中的作用。
from :   

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 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数组

[cpp]  view plain copy
  1. void get_next(const char* ptrn,int* nextval)  
  2. {  
  3.     int plen = strlen(ptrn);  
  4.   
  5.     int i = 0;  
  6.     int k = -1;  
  7.     nextval[i] = -1;  
  8.   
  9.     while(i < plen -1)  
  10.     {  
  11.         if (k == -1 || ptrn[i] == ptrn[k])  
  12.         {  
  13.             ++i;  
  14.             ++k;  
  15.             nextval[i] = k;  
  16.         }  
  17.         else  
  18.         {  
  19.             k = nextval[k];  
  20.         }  
  21.     }  
  22. }  

 

    KMP算法

[cpp]  view plain copy
  1. int KMP_search(const char* src, const char* ptrn, const int *nextval )  
  2. {  
  3.     int i=0;  
  4.     int j=0;  
  5.     int slen = strlen(src);  
  6.     int plen = strlen(ptrn);  
  7.   
  8.     while(i<slen && j<plen)  
  9.     {  
  10.         if (j == -1 || src[i] == ptrn[j])  
  11.         {  
  12.             i++;  
  13.             j++;  
  14.         }  
  15.         else  
  16.         {  
  17.             j = nextval[j];  
  18.         }  
  19.     }  
  20.   
  21.     if ( j >= plen)  
  22.     {  
  23.         return i - plen;  
  24.     }  
  25.     else  
  26.     {  
  27.         return -1;  
  28.     }  
  29. }  


 

参考博客[1]:http://blog.youkuaiyun.com/v_july_v/article/details/7041827

参考博客[2]:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值