一、什么是KMP算法

Knuth-Morris-Pratt 字符串查找算法(常简称为 “KMP算法”)是在一个“主文本字符串” S 内查找一个“词” W 的出现,,以此避免对以前匹配过的字符重新检查。(在原串中匹配模式串)


二、KMP演示


http://staff.ustc.edu.cn/~ypb/jpkc/flash/Find_KMP.swf


三、KMP原理

KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度。


在KMP算法中有个数组,叫做前缀数组,也有的叫,每一个模式串都有一个固定的next数组,,当然它描述的也是子串的对称程度,程度越高,值越大,当然之前可能出现再匹配的机会就更大。


对于next数组的理解,参见http://blog.csdn.net/yearn520/article/details/6729426#t0




 

  1. void SetPrefix(const char *Pattern, int prefix[])  
  2. {  
  3.      int i;  
  4.      int len=strlen(Pattern);//模式字符串长度。  
  5.      prefix[0]=0;  
  6.      for(i=1; i<len; i++)  
  7.      {  
  8.          int k=prefix[i-1];  
  9.          //不断递归判断是否存在子对称,k=0说明不再有子对称,Pattern[i] != Pattern[k]说明虽然对称,但是对称后面的值和当前的字符值不相等,所以继续递推  
  10.          while( Pattern[i] != Pattern[k] && k!=0 )//例i等于14时,求prefix[14]的值  
  11.              k=prefix[k-1]; //继续递归  
  12.          if( Pattern[i] == Pattern[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++  
  13.               prefix[i]=k+1;  
  14.          else  
  15.               prefix[i]=0; //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0  
  16.      }  
  17.   prefix[0]=-1;  
  18. }  

四、测试小例
  1. #include <iostream>  
  2. #include <cstring>  
  3. #include <string>  
  4. using namespace std;  
  5.   
  6. string sorg;  
  7. string spat;  
  8. int prefix[10000];  
  9. int result[20];  
  10.   
  11. void init()  
  12. {  
  13.     sorg="";  
  14.     spat="";  
  15.     memset(prefix,0,sizeof(int)*10000);  
  16.     //memset(result,0,sizeof(int)*20);  
  17. }  
  18. void setprefix(string temp,int next[])  
  19. {  
  20.     int len=temp.size();  
  21.     next[0]=0;  
  22.   
  23.     for(int i=1;i<len;i++)  
  24.     {  
  25.         int k=next[i-1];  
  26.   
  27.         while(temp[k]!=temp[i]&&k!=0)  
  28.             k=next[k-1];  
  29.   
  30.         if(temp[k]==temp[i])  
  31.             next[i]=k+1;  
  32.         else  
  33.             next[i]=0;  
  34.     }  
  35.   
  36.     next[0]=-1;  
  37.   
  38.     for(int i=0;i<len;i++)  
  39.         if(next[i]>=1)  
  40.             next[i]=next[i]-1;  
  41. }  
  42.   
  43. int  kmp(string s1,string s2)  
  44. {  
  45.     int number=0;  
  46.     int i=0;  
  47.     int j=0;  
  48.     while(i<(int)s1.size()&&j<(int)s2.size())  
  49.     {  
  50.         if(j==-1||s1[i]==s2[j])  
  51.         {  
  52.             i++;  
  53.             j++;  
  54.         }  
  55.         else  
  56.             j=prefix[j];  
  57.   
  58.         if(j==s2.size())  
  59.         {  
  60.             i=i-j+1;  
  61.             j=0;  
  62.             number++;  
  63.         }  
  64.     }  
  65.   
  66.     return number;  
  67. }  
  68. int main()  
  69. {  
  70.     int t;  
  71.     cin>>t;  
  72.     memset(result,0,sizeof(int)*20);  
  73.     for(int i=0;i<t;i++)  
  74.     {  
  75.         init();  
  76.         //cout<<"input spat string:"<<endl;  
  77.         cin>>spat;  
  78.   
  79.         //cout<<"input sorg string:"<<endl;  
  80.         cin>>sorg;  
  81.   
  82.         setprefix(spat,prefix);  
  83.         result[i]=kmp(sorg,spat);  
  84.     }  
  85.   
  86.     for(int j=0;j<t;j++)  
  87.         cout<<result[j]<<endl;  
  88.   
  89.   
  90.     return 0;  
  91. }