KMP模式匹配算法

例:

a="abacdaabacdab"

b="abacdab" 

a[i-j+1..i]与b[i..j]相等,随着i增加,j相应的变化,现在比较a[i+1]和b[i+1],若a[i+1]==b[i+1],则i++,j++;否则,若a[i+1]!=b[i+1],调整j的位置,使得  a[i-j+1..i]与b[i..j]保持匹配并且a[i+1]==b[i+1]。如何调整呢?j'要满足b[1..j]中的头j‘个字符与尾j'个字符完全相等,这样变了之后能继续保持i和j的性质,j'越大越好。直到j=m-1时,即b所有字符都匹配,则可返回位置。

若知道int *p,即不等时要退回的位置,可以编写代码如下:

int KMPmatch(char* a, int n, char* b, int m, int* p)
{
int j=0;
for(int i=0; i<n; i++)
{
while(j>0 && a[i] !=b[j])
j=p[j-1];
if(j==m-1)
return i-j;
if(a[i] == b[j])
j++;
}
return -1;
}

现在的问题是怎么求出这个int* p。其对于b的前i个字符,找出前i个字符的头j个与尾j个字符相同的个数。我们可以通过p[1..i]推出p[i+1]。即若b[i+1]=b[j+1],则p[i+1]=p[i]+1;若不等,则将j退回到p[j],再比较是否相等,直到b[i+1]=b[j+1]或j=0,这时p[i]=j。

void KMPfeature(char* b, int n, int* p)
{
p[0]=0;
int j=0;
for(int i=1; i<n; i++)
{
while(j>0 && b[j]!=b[i])
j=p[j];
if(b[j] == b[i])
j++;
p[i]=j;
}
}

测试代码如下:

#include <iostream>

using namespace std;

int main()
{
char* a="abababababababcababababbabcad";
char* b="ababababb";
int n= strlen(a);
int m= strlen(b);
int* p = new int[m];
KMPfeature(b, m, p);
cout << KMPmatch(a, n, b, m ,p)<< endl;
system("pause");
return 0;
}

我们看到,算法需要额外的m个空间来存储特征。m<<n时或要找出b在多个字符串中的位置时使用。

posted on 2011-09-23 19:10  Lovell Liu  阅读(194)  评论(0编辑  收藏  举报

导航