依据上篇的kmp和扩展kmp原理书写的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Kmp(const char *A, const char *B)
{
int lenA = strlen(A);
int lenB = strlen(B);
int *next = (int *)malloc(lenB * sizeof(int));
/* next[i]为满足B[i-z+1..i] == B[0..z-1]的最大的z值, 且要求 z < i + 1
* 例:B = "abab"; next[] = {0, 0, 1, 2};
*/
next[0] = 0;
for (int i = 1, j = 0; i < lenB; i++) {
while (j > 0 && B[i] != B[j])
j = next[j - 1];
if (B[i] == B[j])
j++;
next[i] = j;
}
/* ex[i]为满足A[i-z+1..i] == B[0..z-1]的最大的z值
* 例:B = "abab"; next[] = {0, 0, 1, 2};
* A = "ababacba"; ex[] = {1, 2, 3, 4, 3, 0, 0, 1};
*/
int *ex = (int *)malloc(lenA * sizeof(int));
for (int i = 0, j = 0; i < lenA; i++) {
while (j > 0 && A[i] != B[j])
j = next[j - 1];
if (A[i] == B[j])
j++;
ex[i] = j;
if (j >= lenB)
j = next[j - 1];
}
printf("Kmp:\n");
for (int i = 0; i < lenB; i++) {
printf("%d ", next[i]);
}
printf("\n");
for (int i = 0; i < lenA; i++) {
printf("%d ", ex[i]);
}
printf("\n");
}
void ExtendKmp(const char *A, const char *B)
{
int lenA = strlen(A);
int lenB = strlen(B);
int *next = (int *)malloc(lenB * sizeof(int));
/* next[i]为满足B[i..i+z-1] == B[0..z-1]的最大的z值
* 例:B = "abab"; next[] = {4, 0, 2, 0};
*/
next[0] = lenB;
for (int i = 0; i < lenB - 1; i++) {
if (B[i] != B[i + 1]) {
next[1] = i;
break;
}
}
int a = 1;
for(int k = 2; k < lenB; k++) {
int p = a + next[a] - 1, L = next[k - a];
if (k - 1 + L < p)
next[k] = L;
else {
int i = (p - k + 1) > 0 ? ( p - k + 1) : 0;
while(k + i < lenB && B[k + i] == B[i])
i++;
next[k] = i;
a = k;
}
}
/* ex[i]为满足A[i..i+z-1] == B[0..z-1]的最大的z值
* 例:B = "abab"; next[] = {4, 0, 2, 0};
* A = "ababacba"; ex[] = {4, 0, 3, 0, 1, 0, 0, 1};
*/
int minlen = lenA < lenB ? lenA : lenB;
int *ex = (int *)malloc(lenB * sizeof(int));
for (int i = 0; i < minlen; i++) {
if (A[i] != B[i]) {
ex[0] = i;
break;
}
}
/* 已知 next[0..lenB] 和 ex[0..k-1],求ex[k]
* 前面的匹配过程中到达的最远位置p,p = max(i + ex[i] - 1) (0 <= i <= k - 1),
* a定义为取得最大p值时的i,则==>> A[a..p] = B[0..p-a] ==>> A[k..p] = B[k-a..p-a]
* next[k-a] = L 意味着 B[k-a..k-a+L-1] = B[0..L-1] && B[L] != B[k-a+L]
* 当 k + L - 1 < p 时, ex[k] = L;
* 否则,当 i = 0..n时,依次判断A[k+L+i] 和 B[L+i] 直到两者不相等,此时ex[k] = L + i;
*/
a = 0;
for(int k = 1; k< lenA; k++){
int p = a + ex[a] - 1, L = next[k-a];
if(k - 1 + L < p)
ex[k] = L;
else {
int j= (p - k + 1) > 0 ? (p - k + 1) : 0;
while(k + j < lenA && j < minlen && A[k + j] == B[j])
j++;
ex[k] = j;
a = k;
}
}
printf("ExtendKmp:\n");
for (int i = 0; i < lenB; i++) {
printf("%d ", next[i]);
}
printf("\n");
for (int i = 0; i < lenA; i++) {
printf("%d ", ex[i]);
}
printf("\n");
}
int main(int argc, char **argv)
{
Kmp(argv[1], argv[2]);
ExtendKmp(argv[1], argv[2]);
}