KMP算法是在字符串匹配的过程中利用字符串的相同前后缀信息,跳过不必要的比较,从而提高效率。
核心是根据模式串构造一个数组,数组的第 i个元素表示长度为i的子串里面相当前后缀的长度。
在上图中,输入字符串(模式串)为"ABABACA";数组的第0个元素为0,第一个也为0;第三个元素值为1,表示长度为3的子串"ABA"相同前后缀"A"的长度为1.
假定主串为"bacbababaabcbab",那么其中的一个比较过程如下:
比较失败后,模式串移动到主串的已匹配子串的后缀位置。
代码:
#include <stdio.h>
#include <stdlib.h>
int my_len(char *str)
{
int i = 0;
while(str[i++] != '\0');
return i-1;
}
int * compute_prefix(char *str, int len)
{
int *array = (int *)malloc((len+1) *sizeof(int));
array[1] = 0;
int k = 0;
int i;
for(i = 1; i < len; ++i)
{
while( k > 0 && str[k] != str[i])
{
k = array[k];
}
if( str[k] == str[i])
{
++k;
}
array[i+1] = k;
}
return array;
}
void kmp(char *str, char *pattern)
{
int len1= my_len(str);
int len2 = my_len(pattern);
int *array = compute_prefix(pattern, len2);
int i;
int k = 0;
for(i = 0; i < len1; ++i)
{
while( k > 0 && pattern[k] != str[i])
{
k = array[k];
}
if(pattern[k] == str[i])
{
++k;
}
if(k == len2)
{
printf("find pattern at %d\n", i-k+1);
k = array[k];
}
}
}
int main(void)
{
// char *str = "ababaca";
// int len = my_len(str);
// int *prefix = compute_prefix(str, len);
char *str = "bbc abcdab abcdabcdabde";
char *pattern = "abcdabd";
kmp(str, pattern);
// free(prefix);
return 0;
参考:
https://segmentfault.com/a/1190000008575379?utm_source=tag-newest