疫情封校在宿舍学习KMP算法详解(next数组详解)附例

1.串的模式匹配算法

算法目的:确定主串中所含子串(模式串)第一次出现的位置

算法种类:1.BF算法
2.KMP算法

2.BF算法简单介绍

(1)算法原理

1 .暴力匹配(BF)算法是普通的模式匹配算法,BF算法的思想就是将目标串主串的第一个字符与模式串字串(模式串)的第一个字符进行匹配,
2 .若相等,则继续比较主串的第二个字符和字串(模式串)的第二个字符;
3 .若不相等,则比较主串的第二个字符和字串(模式串)的第一个字符,
4 .每次比较字串(模式串)需要回溯到第一个字符,依次比较,直到得出最后的匹配结果。

(2)过程

设主串s为aaaaab,模式串t为aaab

在这里插入图片描述

第一步 :i=1;j=1;s[i] = t[j] ; i++;j++
第二步 :i=2;j=2;s[i] = t[j] ; i++;j++
第三步 :i=3;j=3;s[i = t[j] ; i++;j++
第四步 :i=4;j=4;s[i] != t[j] ; i++;j++
第五步 :j 回溯到1,j = 1;i 回溯到2;i = 2;重复进行上述过程
代码示例

#include<iostream>
using namespace std;
#include<string>
int BF(string s,string t)
{
    
    
	int len1=s.size();
	int len2=t.size();
	int i=1,j=1;
	while(i<len1&&j<len2)
	{
    
    
		if(s[i]==t[j])
		{
    
    
			i++;j++;//主串和字串依次匹配下一个字符 
			}
		else
		{
    
    
			i=i-j+2;//字串主串回溯开始下一次匹配 
			j=1;
		}
	}
	if(j>=len2)
	return i-len2;//返回匹配第一个字符的下标 
	else 
	return 0;//匹配不成功 
 } 
 int main()
 {
    
    
 	string s="ksdfhuis";
 	string t="fhui";
 	cout<<BF(s,t);
 }

运行结果
在这里插入图片描述

3 .KMP算法详解

1 . KMP算法是解决字符串匹配问题的很高效的一种算法,它的总的设计思想是当在某一个位置出现不匹配的字符时,应尽量向右移动尽可能大的距离,避免重复比较。

KKMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1] 。

因此KMP算法的核心就是引入next函数,将模式串预处理,注意到每次不匹配时要移动的距离只和模式串本身以及不匹配字符在模式串中的位置有关(因为前后缀字符串只与它们有关),所以对于上述例子,我们有:

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

*重点next[ ]的求法

1.手解next数组示例

j : 1 2 3 4 5 6 7
P: a b a b a c
Next[j] : 0 1 1 2 3 4

过程

第1次循环:i = 1,j = 6,j==0成立,i = 2,j = 1, next[2]= 1;

第2次循环:i = 2,j = 1,ch[i]==ch[j]不成立,j = next[j]= next[1]= 0;

第3次循环:i = 2,j = 6,j==0成立,i = 3,j= 1, next[3]= 1;

第4次循环:i = 3, j = 1, ch[i]==ch[j]成立, i = 4,j = 2,next[4】= 2;

第5次循环:i = 4,j = 2,ch[i]==ch[j]成立, i = 5,j = 3,next[5]= 3;

第6次循环:i = 5, j = 3,ch[i]==ch[j]成立,i = 6,j = 4,next[6]= 4;

第7次循环:i = 6,j= 4,ch[i]==ch[j]不成立,j = next[j]= next[4]= 2;

第8次循环:i = 6,j = 2,ch[i]==ch[j]不成立,j= next[j]= next[2]= 1;

第9次循环: i = 6, j = 1, ch[i]==ch[j]不成立,j = next[j]= next[1]= 0;


第10次循环: i = 6, j = θ,j==0成立, i = 7,j = 1, next[7]= 1;

2.理论流程(看不懂没关系)

在这里插入图片描述

3.求next数组代码

void get_next(string T,int next[])
{
    
    
	int i=1,j=0
	next[1]=0;//规定next[1]=0
	while(i<=T.size())
	{
    
    
		if(j==0||T[i]==T[j])
		{
    
    
			next[++i]=++j;
		}
		else
		j=next[j];
	}
}

4 .KMP算法示例

#include<iostream>
#include<string>
using namespace std;
void get_next(string T,int next[])
{
    
    
	int i=1;
	next[1]=0;//规定next[1]=0
	int j=0;
	while(i<=T.size())
	{
    
    
		if(j==0||T[i]==T[j])
		{
    
    
			next[++i]=++j;
		}
		else
		j=next[j];
	}
}
int KMP(string s,string T,int next[])
{
    
    
	get_next(T,next);
	int len1=s.size();
	int len2=T.size();
	int i=1,j=1;
	while(i<len1&&j<len2)
	{
    
    
		if(j==0||s[i]==T[j])
		{
    
    
			i++;j++;//主串和字串依次匹配下一个字符 
		}
		else
		{
    
    
			j=next[j];//i不变,j=next[j]; 
		}
	}
	
	if(j>=len2)
	return i-len2;//返回匹配第一个字符的下标 
	else 
	return 0;//匹配不成功 
}

int main()
{
    
    
	int next[100];
	string s="kfsdghuhsuigh";
 	string t="huhs";
 	//get_next(t,next);
 	if(KMP(s,t,next))
 	cout<<"匹配的位置为"<<KMP(s,t,next);
 	else
 	cout<<"未找到匹配的字符串"<<endl; 
 } 

测试结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_59708493/article/details/122282002