做 KMP 算法首先需要计算一个叫做前缀表的东西。
如上图所示,前缀表里面记录的是最长相等的前后缀长度。
当 b 发生不匹配时,由于前缀表对应的数字是 1,即将数组 P 向右拖到索引为 1 的位置,如上右图。
发现还是匹配不上,继续看前缀表,这时的位置是 0,于是再拖动数组 P,如下作图所示。当不匹配的时候,
前缀表出现 -1,意味着数组 T 的当前索引需要加 1,然后拖动 P 数组使 0 位置与 T 的当前位置对齐,如下右图。
怎么编写代码来获得这个前缀表呢?
void PrefixTable(char pattern[], int prefix[], int n) { int i = 1; int len = 0; prefix[0] = 0; while (i < n) { if (pattern[i] == pattern[len]) { ++len; prefix[i] = len; ++i; } else { if (len > 0) { len = prefix[len - 1]; } else { prefix[i] = len; ++i; } } } } void MovePrefixTable(int prefix[], int n) { for (int i = n - 1; i > 0; --i) { prefix[i] = prefix[i - 1]; } prefix[0] = -1; } void KmpSearch(char text[], char pattern[]) { int i = 0, j = 0; int n = strlen(pattern); int m = strlen(text); int* prefix = (int *)malloc(sizeof(int) * n); PrefixTable(pattern, prefix, n); MovePrefixTable(prefix, n); while (i < m) { if (j == n - 1 && text[i] == pattern[j]) { printf("Found pattern! "); j = prefix[j]; } if (text[i] == pattern[j]) { ++i; ++j; } else { j = prefix[j]; if (j == -1) { ++i; ++j; } } } }