Реализация Кнута-Морриса-Пратта в чистом C
У меня есть следующая KMP-реализация:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int kmp(char substr[], char str[])
{
int i, j, N, M;
N = strlen(str);
M = strlen(substr);
int *d = (int*)malloc(M * sizeof(int));
d[0] = 0;
for(i = 0, j = 0; i < M; i++)
{
while(j > 0 && substr[j] != substr[i])
{
j = d[j - 1];
}
if(substr[j] == substr[i])
{
j++;
d[i] = j;
}
}
for(i = 0, j = 0; i < N; i++)
{
while(j > 0 && substr[j] != str[i])
{
j = d[j - 1];
}
if(substr[j] == str[i])
{
j++;
}
if(j == M)
{
free(d);
return i - j + 1;
}
}
free(d);
return -1;
}
int main(void)
{
char substr[] = "World",
str[] = "Hello World!";
int pos = kmp(substr, str);
printf("position starts at: %i\r\n", pos);
return 0;
}
Вы можете проверить это здесь: http://liveworkspace.org/code/d2e7b3be72083c72ed768720f4716f80
Он хорошо работает на небольших строках, и я проверил его с большой петлей, на этом пути все в порядке.
Но если я изменю искомую подстроку и полную строку на эти:
char substr[] = "%end%",
str[] = "<h1>The result is: <%lua% oleg = { x = 0xa }
table.insert(oleg, y) oleg.y = 5 print(oleg.y) %end%></h1>";
Только после первой попытки эта реализация не удалась...
Пожалуйста, не могли бы вы помочь мне с восстановлением реализации KMP, чтобы алгоритм работал с такими данными в строках...
1 ответ
В одном месте вы отклоняетесь от своего источника, источник имеет
while(j>0 && p[j]!=p[i]) j = d[j-1];
if(p[j]==p[i])
j++;
d[i]=j;
пока у вас есть
while(j > 0 && substr[j] != substr[i])
{
j = d[j - 1];
}
if(substr[j] == substr[i])
{
j++;
d[i] = j;
}
быть обманутым отступом источника. В источнике нет никаких скобок вокруг if()
ветвь, так что только приращение j++;
контролируется if
; d[i] = j;
безусловно.
Тогда источник имеет ошибку, вероятно, из-за необычного использования индексов. Правильный способ настроить массив
int *d = (int*)malloc(M * sizeof(int));
d[0] = 0;
for(i = 1, j = 0; i < M; i++)
{
while(j > 0 && substr[j-1] != substr[i-1])
{
j = d[j - 1];
}
if(substr[j] == substr[i])
j++;
d[i] = j;
}
Но это сбивает с толку, так как установка здесь использует индексы i-1
а также j-1
так же как i
а также j
определить d[i]
, Обычный способ реализовать это отличается; как это реализовано в C#. Так как эту форму вы найдете в большинстве источников, гораздо проще убедить себя в правильности этого.