串模式匹配之------KMP

来源:互联网 发布:vb.net连接本地数据库 编辑:程序博客网 时间:2024/05/27 20:12

       在使用BF算法进行模式匹配时,效率较低,时间复杂度到过了o((n+m)m)后来出现的KMP算法相对于BF算法在效率上有了较大的提高o(m+n)。BF算法效率低是因为每次它的模式串指针都要回溯到开头的位置。如果避免每次都回到开头,那么效率就会提高,这就是KMP的思想之一。

如有 目标串:T(t0t1t2t3.....tk......tm-1)

        模式串:   s(s0s1s2s3...sk.....sk-1)

若模式和目标串在k处出现了不同,则前可以把T改成(s0s1s2s3...sk-1,tk,tk+1.....tm-1)由此看来,每一次比较就没必要从头开始了,在模式串中存在着某种对应关系来确定指针的回溯位置。这种关系我们用“失配函数”来表示。失配函数用一个数组next[j]表示(j模式串的字符个数)next[0]规定为-1。其它的可以用下面的方法确定。

  把j当作失配函数的定义域 其取值范围为 0=<j<s.size();

 k为失配函数的值域,其取值为在0=<k<j中使得p0p1..pk=pk-jpk-j+1...pj成立的K的最大值。

如:s="caatcat"

当j=1时 k=0, s[0]!=s[1] next[1]=-1;

当j=2,k=0,1,  s0s1!=s1s2;s0!=s2,next[2]=-1;

j=3,k=0,1,2;   s0!=s3,s0s1!=s2s3,s0s1s2!=s1s2s3;s[3]=-1;

j=4,k=0,1,2,3 s0=s4,s0s1!=s3s4,s0s1s2!=s2s3s4;s0s1s2s2!=s1s2s3s4;next[4]=0;

j=5,k=0,1,2,3,4 ,s0s1=s4s5;next[5]=1;

j=6,k=0,1,2,3,4,5,next[6]=0;

然后是比较过程:

设T是目标串,S是模式串,并设指针i,j分别指向T,S要比较的字符,开始令i,j都等于0,比较t(i)和S(j)如果相等,则i和j都加1,如果不等,则j回到next[j]。i不变。再用t(i)和s(next[j])比较,如果相等,各回1,如果next[j]=-1则从T(i+1)和t0开始比较。

具体实现如下:

# include <iostream># include <string>using namespace std;//失配函数的实现void nextval(string s,int next[]){    int j=0,k=-1;next[0]=-1;while(j<s.size()){       if(k==-1||s[j]==s[k])   {   j++;   k++;   if(s[j]!=s[k])   next[j]=k;   else   next[j]=next[k];   }   else   k=next[k];}}int find(string s,string t){int next[100],i=0,j=0;      nextval(t,next);  int lens=s.size();  int lent=t.size();  while(i<lens&&j<lent)  {         if(j==-1||s[i]==t[j])  {  i++;  j++;     }  else  {  j=next[j];   }  }  if(j>=t.size())  {   return (i-t.size());  }  else  return -1;}int main(){   string s("abcabaa");    string t("abcaabbabcabaacbacba");int x=find(t,s);if(x==-1)cout<<"查找失败"<<endl;elsecout<<"从第"<<x<<"位开始匹配成功"<<endl;return 0;}


 


 

 

 

原创粉丝点击