推荐博客 :http://www.cnblogs.com/yjiyjige/p/3263858.html
什么是KMP 算法呢 ?
KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。
问题 :
有两个字符串 , 一个叫模式串 , 一个叫主串 , 用模式串向主串匹配 , 传统的方法 , 暴力匹配,当模式串与主串不匹配时 ,模式串与主串都回溯, 用模式串向主串的下一个字母匹配 。
这种暴力匹配效率很低 , 于是就产生了KMP这种思想 : 利用已经部分匹配这个信息,保持主串指针不回溯,通过修改模式串指针,让模式串尽量的移动到有效的位置。
还有这个 :

我感觉 , kmp 就是把人脑一眼可以看到的字符串匹配写成了机器语言 , 好了 , 下面介绍下如何确定 当模式串与主串不匹配时,如何求出模式串应该右移的位数 , 就会引入一个叫 next 的数组 。
next 数组所存的东西就是当两个串不匹配时 , 模式串指针应该跳跃的位置 ,看一个图

如何求next 数组呢 ?
代码示例 :
void getnext(){
int i = 0, j = -1; // i表示后缀指针,j表示前缀指针
next[0] = -1;
while (i != lenp){ // lenp 表示模式串长度
if(j == -1 || s[i] == s[j]) { // s 所存的是模式串
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}
// 前缀时确定的,后缀是相对的
关于next 有两种写法 , 一种是第一个元素内的值为 -1 , 一种是为 0, -1的版本在跳跃移动的时候更好理解一些 。
两个穿匹配的代码示例:
void kmp(){
int i = 0, j = 0;
while (i != lens && j != lenp){
if (s[i] == p[j] || j == -1) { // p 所存的是主串
i++;
j++;
}
else j = next[j]; // 两个串相匹配,当不匹配时,模式串回跳
// 当第一个字母都不匹配时,j 的值会被赋值为 -1
// 当 j 的值等于 模式串长度时,即证明已此时两个串已全部匹配
}
}
举个小例子 :
比如abababab 与 abab 匹配 , 他们上来就可以实现全部匹配 , 接下来 模式串的指针就可以移动到 j = 2 的位置 即 a , 会继续与主串相匹配 。
上面的程序其实是 MP 的代码,它会有一个弊端,如 abcabcd,当第 6 个字母 c 不匹配时会跳到第 3 个字母 c ,其实这样是没有必要的
MP中,P[Next[i]]可能会与P[i]相等,那么其实 还是无法与目标串匹配,在KMP中创建Next数组时,加入了,P[i]不同于P[Next[i]]的条件
MP -> next
void GetNext(char p[],int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
if(j==-1||p[i]==p[j]){
i++;
j++;
Next[i]=j;
}
else{
j=Next[j];
}
}
//Next[m]=0 作用同上
}
KMP -> next
void GetNext(char p[],int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
if(j==-1||p[i]==p[j]){
i++;
j++;
if(p[i]==p[j]){
Next[i]=Next[j];
}
else{
Next[i]=j;
}
}
else{
j=Next[j];
}
}
//Next[m]=0 作用同上
}