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;
}
如输入"ABCABC"改进前Next数组为{0,0,0,1,2};改进后为{0,0,0,0,0}

因此实现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;
}

参考链接:快速模式匹配算法

posted @ 2022-05-06 11:46  涅莫涅  阅读(55)  评论(0)    收藏  举报