KMP算法

KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.KnuthV.R.PrattJ.H.Morris同时发现,因此人们称它为克努特莫里斯普拉特操作(简称KMP算法)。此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作。

首先看下面在一般求子串在主串中的位置的算法。

模式匹配

假设有两个串ST

S = ‘s1s2…sn

T = ‘t1t2…tm

其中0<m≤n

串的模式匹配就是子串的定位操作,即要在S中找出一个与T相同的子串。其中T称为模式串S主串

一般基本思想:从主串Spos个字符起和模式串的第1个字符比较,若相等,则继续依次比较后续字符;否则从主串S的下一个字符起再重新和模式串的第1个字符相比较。以此类推,直至模式串T中的每个字符依次和主串S中的一个连续的字符序列相等,那么就匹配成功,否则就没有匹配成功。

代码:

int index(char *S, char *T, int pos)

{

       i=pos, j=0;

       while( i<length(S) && j< length(T) )

       {

              if( *( S +i) == *(T+j) )

              { j++; i++; }

              else

              { i = i - j + 1; j = 0; }

       }

       if(j >= length(T))

              return i-j;

       else

              return -1;

}

此算法的匹配过程易于理解,效率也较高。不过,在有些情况下,该算法的效率却很低。例如,当模式串为‘000001’,而主串为‘00000000000000000000000001’时。

KMP算法

       KMP算法其实是上面模式匹配算法的一种改进。可以发现,上面的算法每一趟匹配过程中出现字符不等时,回溯指针,如果将其改进,指针不回溯,利用已经得到的部分匹配的结果将模式串向右移动的更远一些,然后继续比较,那么算法性能会得到大大的提高。

 

假设有两个串ST

S = ‘s1s2…sn

T = ‘t1t2…tm

其中0<m≤n

假设匹配过程中产生失配(即si ≠ tj)时,主串S的第i个字符应与模式串的第kk<j)个字符继续比较,则模式串的前k-1个字符必满足下列关系式,且不存在k’>k满足

“t1t2…tk-1” == “si-k+1si-k+2…si-1

而已经得到的部分匹配的结果是:

“tj-k+1t j-k+2…t j-1” == “si-k+1si-k+2…si-1

推得下列等式:

“t1t2…tk-1” == “tj-k+1t j-k+2…t j-1

反之,如果模式串中存在满足的两个子串,则匹配过程中,当主串的第i个字符与模式串的第j个字符失配时,仅需将模式串向右滑动至模式串中第k个字符和主串中的第i字符对齐,匹配仅需从主串的第i个字符与模式串中的第k个字符比较起继续进行。

代码:

//求出子串next数组

void get_next(char *pstr,int *next)

{

       int i=0;

       *next=-1;

       int j=-1;

       while( *(pstr+i) != '/0' )

       {

              if( j==-1 || *(pstr+i)==*(pstr+j) )

              {

                     i++;

                     j++;

                     if( *(pstr+i) != *(pstr+j) )

                            *(next+i)=j;  

                     else

                            *(next+i)=*(next+j);

              }

              else

                     j=*(next+j);

       }

}

 

int index_KMP(char *S, char *T, int pos)

{ 

       i=pos;

       j=0; 

       int *next;   

       next=new int[length(T)];   

       get_next(T, next);  

 

       while( i<length(S) && j<length(T) )   

       {       

              if(*(S+i)==*(T+j) || j==0)       

              { j++; i++; }       

              else

                     j=next[j];

       }   

       if( j >= length(T) )   

              return i-j;

       else

              return -1;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值