以下是本人根据上一篇博客随笔http://www.cnblogs.com/jiayouwyhit/p/3251832.html,所写的KMP算法代码(暂未优化),个人认为在基于上一篇博客的基础上,代码的思路是相对很清晰的。以后的KMP算法求解建议依照此版本进行代码构思。再次强调下本版本的next数组:
例如:
// T = a b c a b c a b c d //下标: 0 1 2 3 4 5 6 7 8 9 //next: -1 0 0 0 1 2 3 4 5 6
该版本的next数组的一个好处在于:字符串的下标是从零开始的,符合C++下string本身的特点;且另next[0]=-1,取值非常巧妙。
//新的KMP算法思路 int myNewKMP(const string& P,const string& T,const int* next) { int P_length = P.size(),T_length = T.size(); int i=0,q=0;//i----主串下标;q---子串下标号 while (i<P_length && q<T_length) { if(q==-1 || P[i]==T[q]) { ++i; ++q; } else{ q=next[q]; } } if(q==T_length) return (i-T_length); else return -1; } //新的求next数组的思路 //next 数组举例示范: // T = a b c a b c a b c d //下标: 0 1 2 3 4 5 6 7 8 9 //next: -1 0 0 0 1 2 3 4 5 6 void myNewNext(const string & T, int *next) { int T_length=T.size(); int k=0,q=1;//k---前缀;q----后缀 next[0]=-1; while (q<T_length) { if(k==-1 ||T[q]==T[k])//K==-1说明K=0了,T[k]!=T[q],故需将q往后移动,而K(也就是next[q])取值为0. { ++q; ++k; next[q]=k; } else k = next[k]; } }
//优化后的 void myNewNextUpdate(const string & T, int *next) { int T_length=T.size(); int k=0,q=1;//k---前缀;q----后缀 next[0]=-1; while (q<T_length) { if(k==-1 ||T[q]==T[k])//K==-1说明K=0了,T[k]!=T[q],故需将q往后移动,而K(也就是next[q])取值为0. { ++q; ++k; //注意:注意这里是++i和++j之后的p[i]、p[j] //修改:因为如果T[q]==T[k],则假如主串中某个字符与T[q]没有匹配上时,则把该字符与T[k]匹配将仍然是匹配不上的。 if(T[q]!=T[k]) next[q]=k; else next[q]=next[k]; } else k = next[k]; } }
int main() { int i; int shift = -1; int next[20]={0}; string P= "ababxbaaaabaaacfdsss"; string T = "aaabaaac"; cout<<"P="<<P<<endl; cout<<"T="<<T<<endl; myNewNext(T,next); if((shift = myNewKMP(P,T,next)) !=-1) cout<<"shift is "<<shift<<endl; for (i = 0; i< T.size(); ++i) { printf("%d ",next[i]); } printf(" "); return 0; }