了解各种关于串的存储结构信息欢迎点击此处,这里就不做赘述,直奔主题。
KMP算法
这种改进算法是由Knuth、Morris和Pratt同时设计完成的,因此简称为KMP算法。此算法可以在O(n+m)的时间数量上完成串的模式匹配操作。其改进在于:每当一趟匹配过程中出现字符比较不等时无需回溯 i 指针,而是利用得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
KMP算法仅当模式与母串之间存在许多“部分匹配”的情况下,才显得比BF算法快得多。但是KMP算法的最大特点是指示母串的指针无需回溯,整个匹配过程中,对母串仅需从头至尾扫描一遍。这对处理从外设输入的庞大文件很有效,可以边读入边匹配,而无需回头重读。
下图为KMP算法的匹配过程
下图是利用模式的next函数进行匹配的过程示例
C++代码
#include<iostream>
using namespace std;
int next[50];
void get_next(string S,int next[])
{
int i = 1;
int j = 0;
next[1] = 0;
while( i < S.size() )
{
if( j==0 || S[i-1]==S[j-1] )//数组下标默认是0开始,第一次比较的位置是0/1,位置1对应着下标0的数据,所以得执行-1操作;
{ //另一种做法是修改字符串s的下标,往上提一位,即下标0不存数据
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}
int KMP(string S,string T,int pos)
{
int i = pos;
int j = 1;
while( i <= S.size() && j <= T.size() )
{
if( j ==0 || S[i-1] == T[j-1] )//0下标有数据,故从0下标开始
{
i++;
j++;
}
else
{
j = next[j];
}
}
if( j > T.size() )
return i - T.size();
return 0;
}
int main()
{
int pos;
string s,t;
while( true )
{
cout<<"请输入母串:";
cin>>s;
cout<<"请输入模式串:";
cin>>t;
get_next(t,next);
cout<<"请输入在母串中开始寻找的位置(小于等于"<<s.size()<<"):";
cin>>pos;
while ( pos > s.size() )
{
cout<<"请重新输入在母串中开始寻找的位置(小于等于"<<s.size()<<"):";
cin>>pos;
}
cout<<"模式串在自母串第 "<<pos<<" 位开始出现的位置为 "<<KMP(s,t,pos)<<endl<<endl;
}
}
结果
请输入母串:fscjnceeskcufnmiercefecn
请输入模式串:ce
请输入在母串中开始寻找的位置(小于等于24):1
模式串在自母串第 1 位开始出现的位置为 6
请输入母串:fscjnceeskcufnmiercefecn
请输入模式串:ce
请输入在母串中开始寻找的位置(小于等于24):7
模式串在自母串第 7 位开始出现的位置为 19
请输入母串:ekuaskcrngmkncmxrucmcfucsrnkmxf
请输入模式串:cmc
请输入在母串中开始寻找的位置(小于等于31):32
请重新输入在母串中开始寻找的位置(小于等于31):31
模式串在自母串第 31 位开始出现的位置为 0
请输入母串:vybucknfaemxlusicbgtnfxmikcgnuml
请输入模式串:si
请输入在母串中开始寻找的位置(小于等于32):33
请重新输入在母串中开始寻找的位置(小于等于32):12
模式串在自母串第 12 位开始出现的位置为 15
请输入母串:
KMP算法和BF算法很相似,但KMP有一个next函数,重点也在这,要理解next函数值计算原理,后面还有一个next函数修正值,有问题可以评论留言。
欢迎各位大佬们指导小弟!
转载需说明!