概述
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。
特点
在整个匹配过程中,指示主串的指针不需要回溯。
代码实现
使用KMP算法时,首先,要求出模式串的next数组。
模式串的next函数的定义:
n e x t [ j ] = { 0 当j=1时 M a x { k ∣ 1 < k < j 且 p 1 . . . p k − 1 = p j − k + 1 . . . p j − 1 } 当此集合不空时 1 其他情况 next[j]=\begin{cases}0&\text{当j=1时}\\Max\{k|1<k<j且p_1...p_{k-1}=p_{j-k+1}...p_{j-1}\}&\text{当此集合不空时}\\1&\text{其他情况}\end{cases} next[j]=⎩⎪⎨⎪⎧0Max{k∣1<k<j且p1...pk−1=pj−k+1...pj−1}1当j=1时当此集合不空时其他情况
代码如下:
#include <iostream>
using namespace std;
//KMP算法
//求next函数值
void get_next(string T, int next[])
{
int i=1;
next[1]=0;
int j=0;
while(i<T[0])
{
if(j==0||T[i]==T[j])
{
++i;
++j;
next[i]=j;
}
else
{
j=next[j];
}
}
}
//求子串位置的定位函数(KMP算法)
int Index_KMP(string S,string T,int a[])
{
int i=1,j=1;
while(i<=S[0]&&j<=T[0])
{
if(j==0||S[i]==T[j])
{
++i;
++j;
}
else
{
j=a[j];
}
}
if(j>T[0])
{
return i-T[0];//匹配成功
}
else
{
return -1;//匹配失败
}
}
//KMP算法测试
int main()
{ //主串
string S="#";//数组0号存储串的长度
//子串
string T="#";//数组0号存储串的长度
string temp;
cout<<"请输入主串:"<<endl;
cin>>temp;
S=S+temp;
cout<<"请输入子串:"<<endl;
cin>>temp;
T=T+temp;
S[0]=S.length()-1;
T[0]=T.length()-1;
int *next = new int[T[0]];
int *nextval = new int[T[0]];
get_next(T,next);
get_nextval(T,nextval);
cout<<Index_KMP(S,T,next)<<endl;
return 0;
}
next函数改进
由于next函数在某些情况下,存在匹配缺陷,因此,可以用nextval函数来代替next函数,具体的匹配算法不变,只是用nextval数组来替代next数组罢了。
nextval函数的实现代码如下:
//求nextval函数值
void get_nextval(string T,int nextval[])
{
int i=1;
nextval[1]=0;
int j=0;
while(i<T[0])
{
if(j==0||T[i]==T[j])
{
++i;
++j;
if(T[i]!=T[j])
{
nextval[i]=j;
}
else
{
nextval[i]=nextval[j];
}
}
else
{
j=nextval[j];
}
}
}
9万+

被折叠的 条评论
为什么被折叠?



