串的KMP算法

KMP算法

目录:

  • KMP的由来
  • next数组的引入
  • 怎样求next数组
  • KMP算法的优化
  • KMP算法的代码实现

1.KMP算法的由来

在这里插入图片描述

在这里插入图片描述
如图所示在朴素的模式匹配算法中当某些子串部分匹配时,主串的扫描指针经常性的回溯,而不是直接性的匹配后面的字符,由此引入KMP算法,把这种问题解决。

2.怎么解决上述问题(next数组的引入)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对于上述过程进行总结:

在这里插入图片描述

kmp算法

在这里插入图片描述

3.next数组的求法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实质:

  • 1.将next[1]=0,next[2]=1.
  • 2,找到当前前j-1个字符
  • 3,分析此子串的前缀和后缀,求出最大相同字符的长度然后+1就是next数组的值

在这里插入图片描述

4.KMP算法的优化

虽然模式匹配算法经过优化的效率有所提升但是还是存在一个问题,就是当字符匹配失败时,前面的字符与当前字符相同的时候,这时候采用KMP算法的模式串依旧指针回溯,就是当前的字符已经不匹配了,没有必要再拿与当前字符相同的字符与对应不匹配的字符进行无意义的比较了,这导致了不必要的开销,因此对KMP算法进行了进一步的优化,将next数组进行优化,让对应next数组内的值“简化”
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.KMP的代码实现

//next数组的算法
//next数组:当模式匹配串失配时,next数组对应的元素指导应该用T串的哪个元素进行下一轮的匹配
void get_next(String T,int *next/*int next[]*/)
{
    int j=0;//前缀
    int i=1;//后缀
    next[1]=0;
   while(i<T.length/*T[0]*/) 
   {
     if(j==0||T[i]==T[j])
      {
         ++i;
         ++j;
         next[i]=j;
       }
      else
          j=next[j];//回溯
   }
}
//完整版代码
#include<stdio.h>
#include<stdlib.h>
typedef char* String;
void get_next(String T,int *next)
{
	int j=0;
	int i=1;
	next[1]=0;
	while(i<T[0])
	{
		if(j==0||T[i]==T[j])
		{
			i++;
			j++;
			next[i]=j;
		}
		else
		{
			 j=next[j];
		}
		  
	}
 } 
 int main()
 {
 	char str[255]=" ababaaaba";
 	int next[255];
 	str[0]=9;
 	get_next(str,next);
 	for(int i=1;i<10;i++)
 	{
 		printf("%d",next[i]);
	 }
 }
//1.普通的KMP
#include<stdio.h>
#include<stdlib.h>
typedef char* String;
void get_next(String T,int *next)
{
	int j=0;
	int i=1;
	next[1]=0;
	while(i<T[0])
	{
		if(j==0||T[i]==T[j])
		{
			i++;
			j++;
			next[i]=j;
		}
		else
		{
			 j=next[j];
		}
		  
	}
 } 
 //若存在,则返回子串T在主串S第pos个字符之后的位置
 // 若不存在,则返回0;
 int index_KMP(String S,String T,int *next)
 {
 	int i=1;
 	int j=1;
 //	int next[255];
 	//get_next[T,next];
 	while(i<=S[0] && j<=T[0])
 	{
 		if(j==0||S[i]==T[j])
 		{
 			i++;
 			j++;
		 }
		 else
		 {
		 	j=next[j];
		 }
	 }
	 if(j>T[0])
	 {
	 	return i-T[0];
	 }
	 else
	 {
	 	return 0;
	 }
  } 
  int main()
  {
  	char s[255]=" aabbababaaaba";
  	char t[255]=" ababaaaba";
  	int next[255];
  	s[0]=13;
  	t[0]=9;
  	get_next(t,next);
  	printf("打印next[i]\n");
  		for(int i=1;i<10;i++)
 	{
 		printf("%d",next[i]);
	 }
	 printf("\n");
	 int index;
	 index=index_KMP(s,t,next);
	 printf("%d\n",index);
	 
  }
//2.KMP优化
#include<stdio.h>
#include<stdlib.h>
typedef char* String;
void get_next(String T,int *next)
{
	int j=0;
	int i=1;
	next[1]=0;
	while(i<T[0])
	{
		if(j==0||T[i]==T[j])
		{
			i++;
			j++;
			if(T[i]!=T[j])
			{
				next[i]=j;
			 } 
			 else
			 {
			 	
			 	next[i]=next[j];
			 }
		
		}
		else
		{
			 j=next[j];
		}
		  
	}
 } 
 //若存在,则返回子串T在主串S第pos个字符之后的位置
 // 若不存在,则返回0;
 int index_KMP(String S,String T,int *next)
 {
 	int i=1;
 	int j=1;
 //	int next[255];
 //	get_next[T,next,1];
 	while(i<=S[0] && j<=T[0])
 	{
 		if(j==0||S[i]==T[j])
 		{
 			i++;
 			j++;
		 }
		 else
		 {
		 	j=next[j];
		 }
	 }
	 if(j>T[0])
	 {
	 	return i-T[0];
	 }
	 else
	 {
	 	return 0;
	 }
  } 
  int main()
  {
  	char s[255]=" aabbababaaaba";
  	char t[255]=" ababaaaba";
  	int next[255];
  	s[0]=13;
  	t[0]=9;
  	get_next(t,next);
  	printf("打印next[i]:\n");
  		for(int i=1;i<10;i++)
 	{
 		printf("%d",next[i]);
	 }
	 printf("\n");
	 printf("子串在主串的位置是\n");
	int index;
	index=index_KMP(s,t,next);
	printf("%d\n",index);
	 
  }

到这里,串的章节就整理完了。之后会更新栈和队列的相关知识。
2020.9.21.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值