关于next数组的求法 数据结构上写的很清楚
做了一个测试看了一些KMP的算法是在一些情况下减少了字符串的比较次数
关键的一点是 KMP算法中主串不用回退了,只用模式串按照next数组中的数回退就可以了
next数组主要分两种情况 一种是没有真子串 则next等于 0
一种是有真子串则next通过k的值回退来求 在纸上画画就应该清楚了
#include <iostream>
using namespace std;
int BF_count = 0,KMP_count = 0;
//******************朴素模式匹配算法(brute force)*******************//
//时间复杂度最好的情况 googlegood长度为m和 google长度为n 时间复杂度为O(n)
//最差情况 00000000000000000000000001长度为m 和0001 长度为n 时间复杂度为 O( (m - n + 1) * n )
int kmp_1(const string & s,const string & t)
{
unsigned s_i = 0,t_i = 0;
while(s_i < s.length() && t_i < t.length())
{
if(s[s_i] == t[t_i] )
{
++s_i;
++t_i;
}
else
{
s_i = s_i - t_i + 1;//s_i回朔到s和t开始比较的下一个位置
t_i = 0;//t_i从头开始匹配
}
BF_count++; //额外用来统计比较的次数
}
if(t_i == t.length())return s_i - t_i;
else return 0;
}
//****************KMP模式匹配算法******************//
void getNext(const string &t,int * next)
{
unsigned j = 1,k = 0;
next[0] = -1;
next[1] = 0;
while(j < t.length() - 1)
{
if(t[j] == t[k])
{
next[j + 1] = k + 1;//先把next赋值好在处理j,k
j++;
k++;
}
else if(k == 0)
{
next[j + 1] = 0;//先把next赋值好在处理j,k
j++;
}
else k = next[k];
}
}
int kmp_2(const string &s,const string & t,const int *next)
{
unsigned s_i = 0 ,t_i = 0;
while(s_i < s.length() && t_i < t.length())
{
if(s[s_i] == t[t_i])
{
s_i++;
t_i++;
}
else if(t_i == 0)s_i++;
else t_i = next[t_i];
KMP_count++;//额外用来统计比较的次数
}
if(t_i == t.length()) return s_i - t_i;
else return 0;
}
int main()
{
string s("goodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgooglegood"),t("google");
unsigned k;
int *next;
next = new int[t.length()];
cout<<"朴素模式匹配算法(Brute Force)..."<<endl;
k = kmp_1(s,t);
cout<<s<<endl<<t<<endl;
cout<<"index = "<<k<<endl;
if(k)
for(unsigned i = 0; i < t.length(); i++)
cout<<s[i + k];
cout<<endl<<"Brute Force 比较次数为:"<<BF_count;
cout<<endl<<endl<<endl;
cout<<"KMP模式匹配算法..."<<endl;
getNext(t,next);
for(unsigned i = 0; i < t.length(); i++)
cout<<next[i]<<" ";
cout<<endl;
k = kmp_2(s,t,next);
cout<<s<<endl<<t<<endl;
cout<<"index = "<<k<<endl;
if(k)
for(unsigned i = 0; i < t.length(); i++)
cout<<s[i + k];
cout<<endl<<"KMP比较次数为:"<<KMP_count;
cout<<endl;
delete []next;
return 0;
}