字符串匹配,KMP算法

来源:互联网 发布:斯维尔算量软件 编辑:程序博客网 时间:2024/06/06 19:58

f[]是失配数组(顾名思义 失配数组记录的就是,原串和模式串若发生不匹配时,模式串应该调回到最近可能匹配的位置)

================================================================================================

KMP可以用来处理如下问题:

用P字符串匹配T字符串,问 T 字符串中出现了几个 和 P 一模一样的子串

================================================================================================

当P[i]与T[k]不一样时(不一样叫失配)

要么从头开始和T[k]匹配(朴素算法就是这样做的,不一样时用P[0]和当前的T[k]匹配)

KMP是用最可能P[f[?]]匹配,?是用find()函数中的while寻找最近的,与当前的T[k]相同的字符

 

================================================================================================

注意失配数组 int f[101], 和模式串 char P[100]数组是大1的(一一对应P的每个字符的失配情况,显然对于P[strlen(s)+1]所对应的情况就是完全匹配时的转移位置)

如 ,对于P(模式串)

P:a s d g w s x f g a s d c d a s d c 

显然蓝色字体与前面的 asd 重复了,所以当再次匹配到 a s d 成功后,若在 c 位置匹配失败(简称失配),则可以移动到f位置匹配,因为之前的asd已经成功了

所以f[c位置] = 3 (P[ f[c位置]] = f)

对于上述的P,可以得到这样的失配数组:

f = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 3, 0 }

因此得到失配数组 f 【i】的含义就是 :字符串P[0]为起点的前缀 和 字符串P[i-1]为终点的后缀  两个字符串的最大匹配字母个数。

 当P数组的第i个字符与文本串T[j]不一样时,用P[ f [i] ] 与文本串T[j] 匹配。注意一点:T[0-j-1] 与 P[ f[i] ]是完全一样的!

如何计算 f 数组:我们用递推的思想,假设我们已经求出f[0] - f[i] , 对于f[i+1] , 直到找到一个能与当前的P[i]字母匹配的前缀为止(空字符与任意字符匹配)。

例1:          
i :                0123456
字符串 P:     abcabab 
f[i] :             00001212
例2:
i  :               01234567
字符串P :     abababab 
f[i] :             000123456

例3:
i :               012345678
字符串P:      ababcdabd 
f[i]:             0001200120

例4:

i :               0123456789

字符串P:      aaabbbaaaa

f[i]:             00120001233

 特别注意:当完全匹配成功时,f【len+1】 = len,( f 数组其实最后是比 P数组 大1的 )

 

================================================================================================

KMP也常用来处理字符串前缀的问题

 最后一个字符的f【】值就是P自身 前缀与后缀的最大匹配值

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. char T[10000],P[100];//从0开始存  
  4. int f[100];//记录P的自我匹配  
  5. void getFail(){  
  6.     int m=strlen(P);  
  7.     f[0]=f[1]=0;  
  8.     for(int i=1;i<m;i++){  
  9.         int j=f[i];  
  10.         while(j&&P[i]!=P[j])j=f[j];  
  11.         f[i+1]= P[i]==P[j] ? j+1 : 0;  
  12.     }  
  13. }  
  14.   
  15. int find(){//返回第一个P 在 T 中出现的位置  
  16.     int len1=strlen(T),len2=strlen(P);  
  17.     getFail();  
  18.     int j=0;  
  19.     for(int i=0;i<len1;i++)  
  20.     {  
  21.         while(j&&P[j]!=T[i])j=f[i];  
  22.         if(P[j]==T[i])j++;  
  23. //到这一步,j就代表 T[i]已经匹配了前面j个P的字符串  
  24.         if(j==len2)return i - len2 + 1;  
  25.         }  
  26.     return -1; //表示 P 不存在于 T   
  27. }  
  28. /* 
  29. int KMP(int *f2, char *S1, char *S2){   //f2是S2的失配数组 
  30.     int pos = 0, len = strlen(S1), j = 0, i = 0;   
  31.     while(i <= len)   
  32.     {   
  33.         while(j!=-1 && S1[i] != S2[j]) j = f2[j];   
  34.         i++, j++;   
  35.         if(i == len)pos = max(pos, j);   
  36.     }   
  37.     return pos;  //这样得到的是S1的尾部和S2的前缀的  最大匹配位置(在S2中的位置) 
  38. } */  

----------------------------------

我们想象一下KMP函数的执行过程:

                   i

                   ↓

S1:ACM MECKSDLF

 

S2:ASFDJKLEDHV

f2:01349098203045 //乱写的

             ↑

              j

显然i是不停→移动,而j是不停进行失配过程。

则当i移动到S1结尾时,j所在的位置就是j所失配的位置。(注意此时i是超过S1的(在最后一个字母后面一位, 且j不一定与S1[i]匹配 ,但S2[j](不包括S2[j]前面的一定与S1匹配)

而pos 是S2的前缀与S1的后缀最大匹配字母数。 因此S2[pos]是不与S1匹配的!

-----------------------------------------
失配数组优化:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void getnext(char *s)    
  2. {    
  3.     int i = 0, j = -1;    
  4.     f[0] = -1;    
  5.     while(i != len)    
  6.     {    
  7.         if(j == -1 || s[i] == s[j])    
  8.             f[++i] = ++j;    
  9.         else    
  10.             j = f[j];    
  11.     }    
  12. }  




优化版失配数组详见:http://blog.csdn.net/niushuai666/article/details/6965517

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 话费缴错了怎么办 网上缴费交错了怎么办 别人给交错话费怎么办 联通流量不到账怎么办 卖家拒绝退款怎么办? 淘宝退款后红包怎么办 手机不能吃鸡怎么办? 在国外手机软件好多不支持怎么办 淘宝店拒绝退款怎么办 app没有退款资格怎么办 手机无法计步怎么办 抖音机型不支持怎么办 用nfc不支持卡片怎么办 移动怎么办省内流量包 手机交不了话费怎么办 淘宝快递不签收怎么办 快递买家不签收怎么办 淘宝退货未收货怎么办 淘宝退衣服运费怎么办 手机流量不到账怎么办 淘宝水果坏了怎么办 用微信充值话费充成空号了怎么办 苹果id被拉黑了怎么办 苹果app不退款怎么办 合同退款不退怎么办 微信充值q币被骗怎么办 小米手机存储空间不够怎么办 小米mix2s存储空间不够怎么办 进货一直没发票怎么办 魅蓝note5卡怎么办 电话费套餐花不了怎么办 墙和床头有间缝怎么办 床板里有虫子怎么办 松木床板味道大怎么办 寝室床板有虫子怎么办 胶合板当床板有气味怎么办 淘宝食品有问题怎么办 淘宝买东西碎了怎么办 被淘宝商家骚扰怎么办 闲鱼被别人拉黑怎么办 三无工厂抓到怎么办