这是上篇kmp算法根据阮景峰博客的教程实现的。
#include<stdio.h>
#include<string.h>
int fun( char *str , int len );
//计算字符串str的部分匹配值,存储在arry数组里
void comp( char *str , int len , int arry[] )
{
int i = 0 , j = 0;
char tmp[ len ];
strcpy( tmp , str );
for( i = 1 ; i < len + 1 ; i++ )
{
tmp[ i ] = '\0';
arry[ i - 1 ] = fun( tmp , i );
strcpy( tmp , str );
}
}
int fun( char *str , int len )
{
int i = 0;
int j = 0;
int count = 0;
//j是计算部分匹配的次数
for( j = 1 ; j < len ; j++ )
{
for( i = 0 ; i < j ; i++ )
{
if( str[ i ] != str[ len - j + i ] ) //str[i]是前缀开始的,str[ len - j + i ]是从后缀开始的
break;
else
{
if( i == j - 1 )
{
count = i + 1 > count ? i + 1 : count; //因为"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度
}
}
}
}
return count;
}
int kmp( char *des , char *src , int arry[] )
{
int i = 0 , j = 0;
int len_des = strlen( des );
while( src[ i ] )
{
if( src[ i ] != des[ j ] )
{
if( j == 0 )
{
i += 1;
}
else
{
i = ( i - j ) + ( j - arry[ j - 1 ] ); //这句很关键,移动的字符串的子串,移动的位数是已匹配的字符数 - 对应数组的值
j = 0;
}
continue;
}
if( j == len_des - 1 )
{
printf( "FIND IT , at position: %d\n" , i - j + 1 );
printf( "%s\n" , src );
for( j = 0 ; j < i - len_des + 1 ; j++ )
printf( "%c" , ' ' );
printf( "%s\n" , des );
return 0;
}
i++;
j++;
}
printf("Not find it!\n");
return 1;
}
int main()
{
char *des = "ABCDABD";
char *src = "BBC ABCDAB ABCDABCDABDE";
// char *des = "abaabcac";
// char *src = "acabaabaabcacaabc";
int arry[ strlen( des ) ];
comp( des , strlen( des ) , arry );
int i = 0;
for( i = 0 ; i < strlen( des ) ; i++ )
printf( "%d\n" , arry[ i ] );
kmp( des , src , arry );
return 0;
}