KMP算法
来源:互联网 发布:如何安装cad软件 编辑:程序博客网 时间:2024/06/05 17:11
在朴素字符串匹配算法中,当匹配失败时,位移加一,也就是模式向后滑动一位,效率较低。我们能否在匹配失败时,利用已有的匹配信息(如当前文本的匹配位置,模式已经匹配的长度等)将模式向后滑动尽可能远的距离呢?
受有限自动机字符串匹配算法启示,利用前缀后缀原理,假设当前字符匹配长度为q(P[1..q]),在匹配P[q+1]时失败了,这时只要找到一个满足Pk为Pq的真后缀的最大k值,我们就可以把模式向后滑动q-k个长度,即位移s’=s+(q-k)。所谓真后缀是因为当前在匹配P[q+1]时已经失败了,模式至少要向后滑动1个长度,也就是说0<=k<q。但是我们注意到s’也不一定是个有效的位移,因为如果此时P[k+1]!=P[q+1],这也是一个无效的位移。再注意到Pk的真后缀P的最长前缀,也是Pq的真后缀,所以我们可以进行递推,直到找到一个合适的k,满足P[k+1]==P[q+1]或k==0。k==0也就是将模式向后移动q个长度,此时匹配长度为0,又开始重新匹配。
模式P的前缀函数next函数的定义如下:
next[q] = max{k|k<q,且Pk为Pq的真后缀},显然next[1]==0。
计算前缀函数的伪代码如下:
Compute-Prefix-Function(P){π[1] == 0//P1的真后缀为空串P0k=0//递归求π[q],2<=q<=mfor q=2 to m {//进入循环说明已经匹配了q-1个字符//且进入循环时有k==π[q-1] while(k>0 and P[k+1] ≠P[q]) { k =π(k)//找下一个真后缀 } if(P[k+1] ==P[q])//说明找到了合适的k值 then k++ π[q] = k }return π;}
利用计算好的前缀函数,仅扫描一遍文本进行字符串匹配的算法伪代码如下:
KMP-Matcher(T,P){q = 0 //已经匹配的字符数for 1=1 to n{while(q>0 and P[q+1] ≠T[i]){q =π[q]}if(P[q+1]==T[i])then q++if(q==m) { print ”pattern occurs with shift ”i-m q =π[q] }}}
算法的C++实现及测试代码如下:
#include <cstdlib>#include <iostream>#include <cstring>using namespace std;//next数组范围为[0..m-1] void Compute_Prefix_Function(const char* P, int* next, int m){next[0] = -1;int k = -1;for(int q=1; q<m; q++){//此时已经匹配了q个字符,P[0,q-1],并且k=next[q-1]; //即P[0,k]为P[0,q-1]的后缀 ,k=-1时,Pk为空串 while(k>-1 && P[k+1]!=P[q]){k = next[k];}if(P[k+1]==P[q]){k++;}next[q] = k;}}void KMP_Matcher(const char* T, const char*P){int n = strlen(T);int m = strlen(P);int next[m]; Compute_Prefix_Function(P,next,m);int q = -1;//已匹配0个字符 for(int i=0; i<n; i++){while(q>-1 && P[q+1]!=T[i])//进入循环说明P[0..q-1]已经匹配 {q = next[q];}if(P[q+1]==T[i]){q++;}if(q==m-1){cout<<"Pattern occurs with shift "<<i-m+1<<endl;q = next[q];}}}int main(int argc, char *argv[]){const int Max_Length = 1000;char T[Max_Length];char P[Max_Length];while(gets(T)){gets(P);KMP_Matcher(T,P);cout<<"next case:"<<endl;} system("PAUSE"); return EXIT_SUCCESS;}
补充说明:
(1)前面叙述的时候,我们假设数组下标是从1开始的,P0表示空串,在我们实际实现中,数组下标是从0开始的,我们只需简单地用-1表示空串即可,但是我们应该注意到当q==m-1是就表示找到了一个完整的匹配。
(2)如果你觉得上述代码不是很好理解,可以参考算法导论(第二版)P568-P573,多琢磨琢磨,你也可以参考严蔚敏的数据结构(C语言版)的第四章,那里提供了另外一种讲解思路,但是原理是一致的。
(3)算法的预处理时间为O(m),匹配时间为O(n)。
- KMP算法详解 【KMP】
- 【KMP】KMP算法模板
- KMP hihoCoder1015 KMP算法
- kmp算法
- KMP算法
- KMP算法
- KMP算法
- KMP算法
- KMP 算法
- kmp算法
- KMP算法
- kmp算法
- KMP算法
- KMP算法
- kmp算法
- kmp算法
- KMP算法
- KMP算法
- 完数
- C++实例之虚函数(析构函数和普通函数)
- Use exceptions to watch for and handle I/O errors.
- android_launcher的源码详细分析
- c# ref参数使用
- KMP算法
- 系统提示SVCHOST错误,该内存不能为“read”解决办法
- diff和patch使用指南
- Use eof() to read and display a text file.
- 请热爱c++(转自人人)
- bug满天飞的工作心得(2012.08.10)
- MD5代码
- 贝塞尔曲线的数学原理
- While it is not the end of a file, output file line by line