推荐博客 :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 作用同上 }