KMP算法------C语言实现

今天呢,要感谢一位小姐姐,她的笔记帮助我理解了KMP算法。

那什么是KMP算法呢?

KMP算法是在BF算法上进行了优化,KMP算法的初衷是为了消除重复的比较,提高效率。

举个例子:

从S串中找到与T串符合的,仔细观察发现,T串前四个都是a,然后从S串查找的时候,也发现了四个a的情况,这个时候,不同BF算法,BF算法会立刻回溯主指针而KMP算法,在匹配过程中出现字符比较不等的时候,不回溯主指针,而是利用已得到的不匹配的结果,将字串滑动尽可能远的一部分距离,继续进行比较。用图给大家解释一下。

用图解释之前,这里要介绍几个知识点:

前缀:指除了最后一个字符外,一个字符串的全部头部组合,从第一个字母开始组合

后缀:除了第一个字符外,一个字符串的全部尾部组合,从最后一个字母开始组合

最大共有长度:很重要,用来决定移动的距离,前缀和后缀的最长匹配

最大共有长度怎么算呢?

举个例子:以串 aaaac举例

a   前缀:0(解释:除了最后一个字符外,没有其他字符,无法组合)  后缀:0(除了第一个字符外,没有其他字符组合) ,所以最大共有长度为 0

aa 前缀:(解释:除了最后一个字符a,其他字符组合a)  后缀:0(除了第一个字符a,其他字符组合:a),所以前缀和后缀的交集就是a 最大共有长度就是1

aaa  前缀:(解释:除了最后一个字符a,其他字符组合:a,aa)   后缀:0(除了第一个字符a,其他字符,a,aa),所以最大共有长度就是 2

aaaa 前缀:0(解释:除了最后一个字符a,其他字符组合a,aa,aaa)  后缀:0(除了第一个字符a,其他字符组合a,aa,aaa),所以最大共有长度就是 :3

aaaac 前缀:0(解释:除了最后一个字符c,其他字符组合a,aa,aaa,aaaa)  后缀:0(除了第一个字符a,其他字符组合c,ac,aac,aaac.最大共有长度就是 0

所以字串 aaaac的最大共有长度就是:3,用KMP算法时,字串移动三格就行。

上面的步骤呢,我们用一个算法实现,然后记录到部分匹配表里面:

算法用来找到最大共有长度:

 next数组就是部分匹配表。

 

 接下来实现KMP算法:

#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 255
typedef struct HString
{
	char zfc[MAX_SIZE];
	int length;
}HString;

//返回next数组(部分匹配表)
void Get_Next(HString child,int *next); 

//KMP,返回字串在主串中的位置 pos是开始位置,不是开始下标 
int KMPCompare(HString* parents,HString* child,int pos);

int main(void) 
{
	HString parents = {"aaaaaacaaacac",13};
	HString child = {"aaaac",5};
	printf("KMP查询的匹配位置是:%d",KMPCompare(&parents,&child,1));
	return 0;
}

//返回next数组(部分匹配表)
void Get_Next(HString child,int *next)
{
	int i = 0;
	int j = -1;
	next[0] = -1;
	while(i<child.length)
	{
		if(j == -1 ||child.zfc[i]==child.zfc[j])
		{
			i++;
			j++;
			next[i] = j;
		}
		else
		{
			j = next[j];
		}
	}
}

//KMP,返回字串在主串中的位置 
int KMPCompare(HString* parents,HString* child,int pos)
{
	int next[MAX_SIZE];//这就是部分匹配表
	Get_Next(*child,next);
	int i = pos-1; 
	int j = 0;
	while(i<parents->length && j < child->length)
	{
		if(j ==-1 ||parents->zfc[i] == child->zfc[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];		//j回退的最大长度 
		}
		
	}
	if(j == child->length)
	{
		return (i+1)-j;
	} 
	return 0;
}

感谢这位小仙女姐姐的笔记

 大家喜欢记得点个赞,点赞过三个,更新BF算法哦。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Boyer-Moore算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的位置。它的优势在于,在某些情况下,它比传统的字符串匹配算法(如KMP算法)更快。 算法的核心思想是尽可能地跳过主串中不可能存在匹配的位置。具体来说,算法分为两个阶段:预处理阶段和匹配阶段。在预处理阶段,算法需要构造两个数组:坏字符规则和好后缀规则。坏字符规则用于处理主串中与模式串不匹配的字符,好后缀规则用于处理模式串中的后缀字符串。 预处理阶段: 1. 对于模式串中的每个字符,记录它在模式串中最后一次出现的位置。 2. 对于模式串中的每个后缀,找到它在模式串中的另一个位置(不包括最后一个字符),使得该位置到模式串结尾的子串是模式串的后缀,并且该子串不是模式串的整个后缀。 3. 如果模式串中不存在好后缀,那么找到模式串中的最长前缀,使得该前缀等于模式串的后缀。 匹配阶段: 1. 从主串中的第一个字符开始,向右扫描。 2. 对于每个字符,从模式串的最后一个字符开始向左扫描,找到第一个不匹配的字符。 3. 根据坏字符规则和好后缀规则,计算下一次需要跳过的位置。 4. 如果模式串的最后一个字符已经匹配,那么找到了一个匹配。 下面是C语言实现的代码示例: ```c #include <stdio.h> #include <string.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) void generate_bad_char_rule(char pattern[], int pattern_len, int bad_char_rule[]) { int i; for (i = 0; i < 256; i++) { bad_char_rule[i] = pattern_len; } for (i = 0; i < pattern_len; i++) { bad_char_rule[(int) pattern[i]] = pattern_len - i - 1; } } void generate_good_suffix_rule(char pattern[], int pattern_len, int good_suffix_rule[]) { int i, j; int prefix_len = pattern_len; good_suffix_rule[pattern_len - 1] = pattern_len; for (i = pattern_len - 2; i >= 0; i--) { if (prefix_len > i + 1 && pattern[i + 1] != pattern[prefix_len - 1]) { prefix_len = pattern_len - good_suffix_rule[pattern_len - prefix_len + i + 1]; } good_suffix_rule[i] = prefix_len + i; for (j = 0; j < i; j++) { if (pattern[j] == pattern[pattern_len - i + j - 1]) { good_suffix_rule[i] = pattern_len - j - 1; } } } } int boyer_moore(char text[], int text_len, char pattern[], int pattern_len) { int i, j; int bad_char_rule[256]; int good_suffix_rule[256]; generate_bad_char_rule(pattern, pattern_len, bad_char_rule); generate_good_suffix_rule(pattern, pattern_len, good_suffix_rule); for (i = pattern_len - 1, j = i; i < text_len;) { if (pattern[j] == text[i]) { if (j == 0) { return i; } i--; j--; } else { i += bad_char_rule[(int) text[i]]; j = pattern_len - 1; } if (i >= text_len) { break; } if (j == -1) { j = pattern_len - 1; } if (good_suffix_rule[j] < pattern_len - j + i) { i += pattern_len - j - 1; j = pattern_len - 1; } } return -1; } int main(int argc, char *argv[]) { char *text = "ABAAABCD"; char *pattern = "ABC"; int text_len = strlen(text); int pattern_len = strlen(pattern); int index = boyer_moore(text, text_len, pattern, pattern_len); if (index >= 0) { printf("Pattern found at index %d\n", index); } else { printf("Pattern not found\n"); } return 0; } ``` 在上面的代码中,`generate_bad_char_rule`函数用于生成坏字符规则,`generate_good_suffix_rule`函数用于生成好后缀规则,`boyer_moore`函数用于实现匹配。在主函数中,我们将一个文本串和一个模式串传递给`boyer_moore`函数,并打印出匹配结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值