下面是c语言写的KMP,根据B站正月点灯笼视频学习打的代码,真心推荐大家可以看看,里面讲的许多算法非常好.
/*通过prefix函数去实现KMP的前缀表,前缀表第一个一般可以是0,也可以设置成-1,设置成-1可
以通过move这个函数题去实现
同事这个是简单的KMp算法的实现步骤,还可以优化,让效率更快
prefix从下标为0开始存储
prifix第一个是负一时候,所有prefix[x]看的是所对应字符前面的字符前缀和后缀相等的量,
第一个字符prefix[0]的相等量设置为-1,第二个字符prefix[1]量看的是他前面字符也就是第一个字符,
前缀后缀都是那个字符串本身的话不算相等.
等于0时候匹配时候是算上自己去匹配,两者情况都可以使用,看你个人的情况.
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//prefix代表前缀 pattern是指需要求前缀表的那个字符串
void prefix_table(char pattern[], int prefix[], int n){
prefix[0] = 0;//前缀是从0开始
int len = 0;//刚开始前后缀相等初始化为0,刚好pattern[len]指向下一个,如果下面有和这个相等的直接加len1,
int i = 1;
while (i < n) {
if (pattern[i] == pattern[len]) {//可以看B站正月点灯笼KMP2 6分04秒
len++;
prefix[i] = len;
i++;
}
else
{ if(len>0)
{
len = prefix[len - 1];//大话数据结构书上138页,得出的规律,
/* 下面的话来自up主下面的评论:当两个字符串不适配的时候,回溯回退的位置始终是模式串的不适
配字符的上一位字符前后缀相同的位置,求next数组,前缀与后缀不
适配时,同样是移动模式串,只不过这个模式串是自身的前缀部分
.而视频中的len恰好指向了这个模式串,但是要找自身的前一位 所以prefix【len-1】*/
}
else
{
prefix[i] = len;
i++;
}
}
}
}
//移动成开头是-1的情况,第一个编程-1,其他的位置一次继承后一个的值
void move_prefix_table(int prefix[], int n)
{
int i;
for (i = n - 1; i > 0; i--)
{
prefix[i] = prefix[i - 1];
}
prefix[0] = -1;
}
void kmp_search(char text[], char pattern[])
{
int n = strlen(pattern);
int m = strlen(text);
int* prefix = malloc(sizeof(int) * n);//为这个数组动态申请空间大小
prefix_table(pattern, prefix, n);
move_prefix_table(prefix, n);
int i = 0;
int j = 0;
//规定 text[i] , len(text) = m 主串
// pattern[j] ,len(pattern)=n 需要和主串匹配的串
while (i < m)
{
if (j == n - 1 && text[i] == pattern[j])
{
printf("Found pattern at %d\n", i - j);
j = prefix[j];
}
if (text[i] == pattern[j])
{
i++; j++;
}
else
{
j = prefix[j];
if (j == -1)
{
i++; j++;
}
}
}
}
int main(void)
{
char pattern[] = "ABABCABAA";
char text[] = "ABABABCABAABABABAB";
kmp_search(text, pattern);
/*
int prefix[9];
int n = 9;
prefix_table(pattern, prefix, n);
moce_prefix_table(prefix,n);
int i;
for (i = 0; i < n; i++)
{
printf("%d\n", prefix[i]);
}*/
return 0;
}