这是我对 KMP字符串匹配算法的实现。 当我检查pi数组时,它存储0,1,2,3,4,5,6。但根据算法书,它应该是0,0,1,2,3,0,1。我的代码也给出了正确的结果。我不明白为什么会这样,或者我做错了什么?如果是的话,请指正。
感谢。
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
int* ComputePrefix(char P[])
{
size_t m = strlen(P);
int *pi = new int[m];
pi[0] = 0;
int k = 0;
for(int q =0; q < m; q++)
{
if( k > 0 && P[k+1] != P[q])
k = pi[k];
if( P[k+1] == P[q])
{
pi[q] = k;
k = k + 1;
}
pi[q]=k;
}
return (pi);
}
void KMP_Matcher(char T[], char P[])
{
size_t n = strlen(T);
size_t m = strlen(P);
int *pi = new int[m];
pi = ComputePrefix(P);
cout<<endl;
int q =0;
for (int i = 0; i <= n; i++)
{
if( q > 0 && P[q] != T[i] )
{
q = pi[q - 1];
}
else if( P[q] == T[i])
{
if( q == m-1)
{
cout<<"Shift occurs at : "<< i-q <<endl;
q = pi[q];
}
else q = q + 1;
}
else q++;
}
}
int main()
{
char T[] = "abababacaba";
char P[] = "ababaca";
KMP_Matcher(T,P);
return 0;
}
答案 0 :(得分:1)
您的跳转表构建功能根本不会检查针的前缀。我们希望能够针对针中的每个位置查找导致(但不包括)该位置的针的最长正确前缀的长度,而不是完整前缀从needle[0]
开始,但未能匹配;这是我们在寻找下一场比赛时必须回溯的距离。因此,跳转表中的每个条目(例如,table[i]
)正好是针的最长可能前缀的长度,该前缀也是以needle[i - 1]
结尾的子字符串的前缀。
跳转表中的前两个条目是-1和0,因为a)模式开头的不匹配不会触发回溯(换句话说,零长度的前缀不能有任何正确的前缀或后缀)和b)空字符串被认为是长度为0。
有关详细信息,请查看wikipedia或算法教科书。
完成上述任务的代码是:
int *build_jump_table(const char * target)
{
if(!target)
return NULL;
int *table = new int[strlen(target) + 1];
if(!table)
return NULL;
table[0] = -1; /* unused by the matcher, just used here */
for(int i = 0; target[i] != '\0'; i++) {
table[i+1] = table[i] + 1;
while(table[i+1] > 0 && target[i] != target[table[i+1] - 1]) {
table[i + 1] = table[table[i + 1] - 1] + 1;
}
}
return table;
}
非常冗长,当您理解跳转表背后的概念时,可以简化很多。