废话少说,我把代码弄上去,以免以后忘记了,算是做个纪念吧。
#include <string>
#include <iostream>
using namespace std;
void GetNext(char str[],int Next[]);
void GetNextval(char str[],int Nextval[]);
int KMP(string T,string str,int *Next);
int main(int argc, char* argv[])
{
char str[]="ababcabcacbab";
char str1[]="abcac";
int *Next=new int[strlen(str1)];
int *Nextval=new int[strlen(str1)];
GetNext(str1,Next);
cout<<"首先得到Next的值:"<<endl;
for(int i=0;i<strlen(str1);i++)
cout<<Next[i]<<",";
cout<<"\n进行KMP的字符串匹配后,得到了字串跟模式串匹配的字符串所在位置:\n";
cout<<KMP(str,str1,Next)<<endl;
cout<<"修正得到Next的值:"<<endl;
GetNextval(str1,Nextval);
for(int p=0;p<strlen(str1);p++)
cout<<Nextval[p]<<",";
cout<<"\n"<<KMP(str,str1,Nextval);
return 0;
}
//得到Next的值
void GetNext(char str[],int Next[])
{
string Str1=str;
int j=-1,i=0;
Next[0]=-1;
while(i<Str1.length()-1)
{
if(j==-1||str[i]==str[j])
{
i++;
j++;
Next[i]=j;
}
else
j=Next[j];
}
cout<<endl;
}
//经过修正后的Next函数
void GetNextval(char str[],int Nextval[])
{
string Str1=str;
int j=-1,i=0;
Nextval[0]=-1;
while(i<Str1.length()-1)
{
if(j==-1||str[i]==str[j])
{
i++;
j++;
if(str[i]!=str[j])
{
Nextval[i]=j;
}
else
Nextval[i]=Nextval[j];
}
else
j=Nextval[j];
}
cout<<endl;
}
//进行模式串的匹配
int KMP(string T,string str,int *Next)
{
int i=0,j=0;
while(i<str.length()&&j<T.length())
{
if(str[i]==T[j])
{
i++;
j++;
}
else
{
i=Next[i];
if(i==-1)
{
j++;
i=0; }
}
}
return j-i+1;
}
首先需要知道模式串的匹配,如果要想做到效率高的话,就不能一步一步的往前挪动,
但是对于主串还是一步步往前面指定的元素移动的,只是对于模式串来说就不能每一次都从第一个字符来比较,这样虽然能成功但是效率很低。
就像“000000000000001”和“0001”这两个字符串,如果你一步步的往前面移动,然后遍历
你的模式串,这样的话效率很低,但是当你用了KMP算法后,你这个模式串与主串的比较就只需要11次 ,但是你如果一步步的移动的话,要比较15*4次,这样效率就低了很多。
所以KMP算法就发挥了优势,首先需要弄明白的是Next的值,Next的值其实也就是遍历,你从第一个字符开始依次得到每一个字符的Next的值。当你求后面的字符的Next值的时候,需要用到前面的字符的Next的值,这就是KMP不是很好理解的地方。
上面的代码还修正了Next的值,经过修正的Next的值的效率更高。