kmp算法及其优化

KMP算法及其优化

为什么要使用kmp算法?

传统的字符串模式匹配主串和字串的指针在不匹配时都要重复的进行回退。而有些回退的比较意义不大。这就造成了算法的效率不高。时间复杂度为o(mn)。而kmp算法恰恰就是为了解决这一个问题而产生的。在kmp算法中主串指针不必回退。而下一次用字串的哪个字符去匹配只与字串有关,与主串无关,这也就大大的提高了算法的效率,时间复杂度优化到了o(m+n)。

kmp算法的灵魂(next数组)

手算方式1(好理解方便做题的方式)


也就是说无论字串是什么next[1]的值都是0;

在这里插入图片描述
当第二个不匹配的时候,模式串向后滑动一定是从第一个进行比较所以无论子串是什么值next[2]都等于1.
在这里插入图片描述
当在第四个元素失配的时候在第四个元素前画一条线。移动子串直到移动后线前的元素再次与移动前的线前元素匹配时,线后第一个元素所指的位置即为next值。之后next[j]的求法与之相同。

手算方法2(和机算方法类似)

方法二主要的思想是算相同的前缀和后缀的最大长度+1。下面是这个方法的演示。
在这里插入图片描述

kmp算法求next数组C语言代码实现

void getnext(string t ,int next[]){
	     int j=0;//前缀的最后一个元素
		 int i=1;//后缀的最后一个元素
		 next[1]=0;
		 while(i<t.length){
		 if(j==0||t.data[i]==t.data[j]){
		 	i++;
		 	j++;
		 	next[i]=j;
		 } 
		 else{
		 	j=next[j];//回溯去找到那个最长的前缀 
		     }
	 }
}

代码分析

在这里插入图片描述

代码优化

这段代码在某些类型的字符串中还是会出现缺陷的。如串aaaaab。下面来分析一下它的缺陷及优化思路。
在这里插入图片描述

kmp算法优化后完整实现C语言

#include<stdio.h>
#include<stdlib.h>
#define maxsize 255
 typedef struct {
	char data[maxsize];
	int length;
}string;
void init(string &s){
	s.length=0;
} 
void create(string &s){
	init(s);
	char x;
	printf("请输入串($结束):\n");
	scanf(" %c",&x);//前面加个空格防止把回车当成下一个串的输入 
	int i=1;
	while(x!='$'){
		s.data[i++]=x;
		s.length++;
		scanf(" %c",&x);
	}
	printf("串为\n"); 
	for(int i=1;i<=s.length;i++){
		printf("%c ",s.data[i]);
	} 
	printf("\n"); 
} 
void getnext(string t ,int next[]){
	     int j=0;//前缀的最后一个元素
		 int i=1;//后缀的最后一个元素
		 next[1]=0;
		 while(i<t.length){
		 if(j==0||t.data[i]==t.data[j]){
		 	i++;
		 	j++;
		 	if(t.data[i]!=t.data[j])//如果是相等的再比较时必然还会适配,重复了很多次无用比较效率低。 
		 	{
		 		next[i]=j;
			 }
			 else{
			 	next[i]=next[j];//这个时候回溯到层的next看什么时候相不等,直到不等才有意义。 
			 }
		 } 
		 else{
		 	j=next[j];//回溯去找到那个最长的前缀 
		 }
	 }
}
int indexkmp(string s,string t,int next[]) 
{
	int i=1,j=1;
	while(i<=s.length&&j<=t.length){
		if(j==0||s.data[i]==t.data[j]){
			i++;
			j++;
		}
		else {
			j=next[j];
		}
	}
	if(j>t.length){
		printf("匹配成功") ; 
		printf("%d ",i-t.length) ;
	}
	 else {
	 	printf("匹配失败") ; 
	 	
	 }
	 
}
int main(){
	string s,t;
	int next[maxsize];
	create(s);
	create(t);
	getnext(t,next);
	indexkmp(s,t,next);
	return 0;
	
}
  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值