下面是自己写的一个KMP算法实现。P为待查找串,Q为模式串,B为预处理数组。
#include <stdio.h>
#include <stdlib.h>
#define MATCH_DETAIL 1
#if MATCH_DETAIL
void print_strP( char* P, int num )
{
int i;
printf("\nP:%d\t", num - 1);
for ( i = 0; i < num; i++ )
printf("%3c", P[i]);
printf("\n");
}
void print_strQ( char* Q, int num, int indent )
{
int i;
printf("\nQ:%d\t", num - 1);
/* keep indent */
for ( i = 0; i < indent; i++ )
printf("%3c", ' ');
for ( i = 0; i < num; i++ )
printf("%3c", Q[i]);
printf("\n");
}
void print_arrB( int* B, int num, int indent )
{
int i;
printf("B:%d\t", num - 1);
/* keep indent */
for ( i = 0; i < indent; i++ )
printf("%3c", ' ');
for ( i = 0; i < num; i++ )
printf("%3d", B[i]);
printf("\n\n");
}
void show_status( char* P, char* Q, int* B, int s, int t)
{
if ( P == NULL || Q == NULL || B == NULL )
return;
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
print_strP( P, s + 1 );
print_strQ( Q, t + 1, s - t );
print_arrB( B, t + 1, s - t );
}
#endif
void preprocess( char* Q, int* B )
{
int i;
int j;
if ( Q == NULL || B == NULL )
return;
i = 1;
j = 0;
B[0] = 0;
while ( Q[i] != '\0' ) {
while ( j > 0 && Q[j] != Q[i] ) {
j = B[j - 1];
}
if ( Q[j] == Q[i] )
j++;
B[i] = j;
i++;
}
#if MATCH_DETAIL
printf("preprocess string Q\n");
print_strQ( Q, strlen(Q), 0 );
print_arrB( B, strlen(Q), 0 );
#endif
}
void KMP( char* P, char* Q )
{
int i;
int j;
int *B;
if ( P == NULL || Q == NULL )
return;
B = (int *)malloc( strlen(Q) );
if ( B == NULL ) return;
preprocess(Q, B);
i = j = 0;
while ( P[i] != '\0' ) {
/* if Q[j] cannot match P[i], change j to proper value and stop at zero */
while ( j > 0 && Q[j] != P[i] ) {
#if MATCH_DETAIL
show_status( P, Q, B, i, j );
#endif
j = B[j - 1];
}
/* current characters are matched, increase j */
if ( Q[j] == P[i] )
j++;
#if MATCH_DETAIL
else
show_status( P, Q, B, i, j );
#endif
i++;
if ( Q[j] == '\0' ) {
#if MATCH_DETAIL
show_status( P, Q, B, i - 1, j - 1 );
#endif
printf("Pattern matches at shift %d\n", i - j);
// find next pattern string
j = 0;
}
}
}
int main( void )
{
char* P = "ababcabdbabcabcda";
char* Q = "abcabcd";
#if MATCH_DETAIL
printf("string P:\n");
print_strP( P, strlen(P) );
printf("string Q:\n");
print_strQ( Q, strlen(Q), 0 );
#endif
KMP( P, Q );
return 0;
}