c语言 KMP算法解练
-
概述
KMP算法是一种字符串的模式匹配算法,用于判断两个字符串之间的关系(含于,相同等)一般的,普通模式匹配算法为将字串与母串进行逐字对比进行判断
![]()
![]()
如上图所示当子串与母串对应字符相同时继续比较,直到结束比较或出现不同
![]()
![]()
当不同时字串回到首字符从母串下一个字符继续比较,可见这样效率是很低的做了许多无用功,KMP算法就利用匹配失败后的信息对下一个需进行比较的字符进行定位(当出现上图情况时,KMP算法进行的结果如下)
![]()
这样就省去了比较母串中‘B''C'字符的过程 -
KMP算法的实现
![]()
总结规律可知当可快速比较时,母串上一次比较不相同的字符位置(记为j)对应的子串位置其前面所有字符(记为n个)与子串上一次比较不相同的字符位置(记为i)前n个字符相同
进一步推知子串每个字符(i)都有其对应的 字符(j )可快速跳转比较,而母串 j 位置前字符串与字串 i 位置前字符串完全相同,所以可编写一个函数求得子串每一个字符的 j ,将之存放于一个数组中(记为next[]数组),代码如下
点击查看代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
static int* Next(char* s)
{
int len2 = strlen(s);
int* next = malloc(sizeof(int) * len2);
next[0] = 0;
next[1] = 0;//任何字符串前两位字符next数组为0
int i = 1;
int j = 0;
while (i < len2 - 1)
{
//字符串s与自身比较获取每个字符的“j”
//所求字符为s[i+1]
if (s[i] == s[j])
{
i++;
j++;
next[i] = j;
}
else
{
if (j == 0)
{
i++;
next[i] = 0;
}
j = next[j];//比较后若不相同对j进行重定向
}
}
for (int i = 0; i < len2; i++)
{
printf("%d\n", next[i]);
}
return next;
}
如输入"ABCABD"其Next数组为{0,0,0,1,2}
只要利用next数组的内容即更快速的进行字符串的模式匹配,但此时Next函数存在一个缺陷如下情况,其实 j 位置对应的字符是不相同的,如果是人为判断的话,会直接跳过该步,而不做此多余的步骤

经改进后的Next函数如下:
点击查看代码
static int* Next(char* s)
{
int len2 = strlen(s);
int* next = malloc(sizeof(int) * len2);
next[0] = 0;
next[1] = 0;
int i = 1;
int j = 0;
while (i < len2 - 1)
{
if (s[i] == s[j])
{
//增加一步对j+1和i+1位置字符进行判断
if (s[i + 1] != s[j + 1])
{
next[i + 1] = j + 1;
}
else
{
next[i + 1] = next[j];
}
i++;
j++;
}
else
{
if (0 == j)
{
i++;
next[i] = 0;
}
j = next[j];
}
}
for (int i = 0; i < len2; i++)
{
printf("%d\n", next[i]);
}
return next;
}
因此实现KMP算法的代码如下
点击查看代码
static int KMP(char* s1, char* s2)
{
int len1 = strlen(s1);
int len2 = strlen(s2);
int* next = Next(s2);
int k = 0;
for (int i = 0; i < len1; i++)
{
if (next[k] > 0)
i--;
for (int j = next[k]; j < len2; j++)
{
if (s2[j] != s1[i + j])
{
k = j;
i += j;
break;
}
if (j == len2 - 1)
{
free(next);
return 1;
}
}
}
free(next);
return 0;
}
参考链接:快速模式匹配算法







浙公网安备 33010602011771号