从文本中找出匹配的单词或者字符串,使用kmp算法,效率提升很多,可以防止多次重复比较,浪费时间;前提是需要找到该字符串的公共前后缀,不至于从头比较:
大致思路如下:
如:
T : a a a a a a a a b
P : a a a a b
找出P的公共前后缀:
0: a
1 : a a
2 : a a a
3 : a a a a
: a a a a b //总共五个字符,所以将前面的数组下移:
-1 : a
0 : a a
1 : a a a
2 : a a a a
3 : a a a a b
所以:
T : a a a a a a a a b
p[] 0 1 2 3 4
P : a a a a b
前缀-1 0 1 2 3
然后对比T与P,发现在T(a) &P(b)处不同,此时P(b)对应前缀表为3,找出上标p[3]处的字符移动到
匹配T(a)错误的地方,继续从匹配失误的地方开始比较
*
T : a a a a a a a a b
a a a a b
p[] 0 1 2 3 4
P : a a a a b
前缀 -1 0 1 2 3
从匹配失误的地方开始比较,此时还是不匹配,在此处继续根据前后缀找出p[3],继续移动:
T : a a a a a a a a b
a a a a b
然后继续从匹配失误的地方进行比较,直到匹配或者对比完数组:
T : a a a a a a a a b
a a a a b
T : a a a a a a a a b
a a a a b
可以先写出前后缀数组的解法:
void profix_table(char pattern[], int profix[], int n)
{
profix[0] = 0;
int len =0; i = 1;
while(i < n){
if(pattern[i] == pattern[len] //对比前后两个指针指向的值进行对比,如果相等则更新prefix[],继续移动指针
{
len++;
profix[i] = len; //len 为i 位置的前后缀长度
i++;
}else{
if(len > 0)//如果不相等,则分len是否大于0讨论
{
len = prefix [ len-1 ]; //len回退一位,找对应的prefix[len- 1],此时len也会指向p[ prefix[len-1] ]的位置
}
else{
prefix[i] = len;
}
}
}
void move_profix( int profix[], int n)
{
int i;
for( i = n-1 ; i > 0; i--)
{
profix[i] = profix [i-1];
}
profix[0] = -1;
}
void kmp(char text[], char pattern)
{
int n = strlen(pattern);
int* prefix = malloc(sizeof(int) * n);
prefix_table(pattern, prefix, n);
move_profix(prefix, n);
int m = strlen(text);
int i = 0, j = 0;
while(i < m)
{
if(j == n-1 && text[i] == pattern[j])
{
printf("pattern found at %d\n", i - j);
j = prefix[j];//此处是找到一组后可以继续找下一组
}
if(text[i] == pattern[j])
{
i++; j++;
}else
{
j = prefix[j]; //匹配失误,则回退pattern[j],根据prefix[j]找出对应的pattern[]
if(j == -1)
{
i++; j++;
}
}
}
}

本文深入讲解了KMP算法的工作原理及实现过程,包括如何构建公共前后缀数组,以及如何利用这些信息来提高文本搜索的效率。通过具体示例,详细说明了算法在遇到不匹配时的处理方式,使读者能够理解并掌握这一高效字符串匹配算法。
626

被折叠的 条评论
为什么被折叠?



