KMP算法的实现
2016-08-11 10:51
295 查看
概念:
Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP 算法”,常用于在一个文本串 S 内查找一个模式串 P 的出现位置,这个算法由 Donald Knuth、Vaughan Pratt、James H. Morris 三人于 1977 年联合发表,故取这三人的姓氏命名此算法。
下面先直接给出 KMP 的算法流程:
假设现在文本串 S 匹配到 i 位置,模式串 P 匹配到 j 位置:
如果 j = -1,或者当前字符匹配成功(即 S[i] == P[j]),都令 i++,j++,继续匹配下一个字符;
如果 j != -1,且当前字符匹配失败(即 S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串 P 相对于文本串 S 向右移动了 j - next [j] 位。
现在我们关系的是next数组,那next数组是如何求得呢?
举例:给定字符串“ABCDABD”,可求得它的 next 数组如下:
实现原理:计算 next 数组的方法可以采用递推:
1.如果对于值 k,已有 p0i,p1, ..., pk-1 = pi-k,pi-k+1, ..., pi-1,相当于 next[i] = k。 可以理解为next[i] = k 代表 p[i] 之前的模式串子串中,有长度为 k 的相同前缀和后缀。
2.下面的问题是:已知 next [0, ..., i],如何求出 next [i + 1] 呢?
若p[k] == p[i],则 next[i+ 1 ] = next [i] + 1 = k + 1;
若p[k ] ≠ p[i],如果此时 p[ next[k] ] == p[i ],则 next[ i + 1 ] = next[k] + 1,否则继续递归前缀索引 k = next[k],而后重复此过程。
Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP 算法”,常用于在一个文本串 S 内查找一个模式串 P 的出现位置,这个算法由 Donald Knuth、Vaughan Pratt、James H. Morris 三人于 1977 年联合发表,故取这三人的姓氏命名此算法。
下面先直接给出 KMP 的算法流程:
假设现在文本串 S 匹配到 i 位置,模式串 P 匹配到 j 位置:
如果 j = -1,或者当前字符匹配成功(即 S[i] == P[j]),都令 i++,j++,继续匹配下一个字符;
如果 j != -1,且当前字符匹配失败(即 S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串 P 相对于文本串 S 向右移动了 j - next [j] 位。
现在我们关系的是next数组,那next数组是如何求得呢?
举例:给定字符串“ABCDABD”,可求得它的 next 数组如下:
实现原理:计算 next 数组的方法可以采用递推:
1.如果对于值 k,已有 p0i,p1, ..., pk-1 = pi-k,pi-k+1, ..., pi-1,相当于 next[i] = k。 可以理解为next[i] = k 代表 p[i] 之前的模式串子串中,有长度为 k 的相同前缀和后缀。
2.下面的问题是:已知 next [0, ..., i],如何求出 next [i + 1] 呢?
若p[k] == p[i],则 next[i+ 1 ] = next [i] + 1 = k + 1;
若p[k ] ≠ p[i],如果此时 p[ next[k] ] == p[i ],则 next[ i + 1 ] = next[k] + 1,否则继续递归前缀索引 k = next[k],而后重复此过程。
#include<iostream> using namespace std; //求next值 void CalNext(const char *sub, int n, int *next) { int i=0,k=-1; next[0] = -1; while(i<n-1)//注意是n-1,否则会越界 { if(k==-1||sub[i] == sub[k]) { next[++i] = ++k; } else { k = next[k]; } } for(int i=0; i<n; i++) //打印测试 { cout<<next[i]<<" "; } cout<<endl; } int KMP(const char *str, const char *sub) { if(str == NULL || sub == NULL) return -1; int i=0,j=0; int len1 = strlen(str); int len2 = strlen(sub); //////////////////////////// int *next = new int[len2]; CalNext(sub, len2, next); /////////////////////////// while(i<len1&&j<len2) { if(j==-1 || str[i] == sub[j]) { i++; j++; } else { j = next[j]; } } ////////////////////////// delete [] next; if(j == len2) return i-j; return -1; } int main() { char *str = "aaaaaaaaaaaaabbb"; char *sub = "aaaaabb"; int index = KMP(str, sub); cout<<index<<endl; return 0; }
相关文章推荐
- java下载文件名,浏览器弹出框中文件名丢失问题
- Java多线程拾遗
- 部署flask1
- ZZULIOJ-1913-小火山的计算能力(模拟)
- SQL Server创建和使用临时表(转)
- 【zzulioj 1908 小火山的围棋梦想】
- 航班时刻票价查询
- Android Platform Version与API Level的对应表
- 过滤器
- 过滤器
- PAT 1013. Battle Over Cities
- Java取整
- 重定向子进程标准输入输出
- 玛卡玛卡滋蛋仔
- 记一次服务器timewait事件 推荐
- 图论 最短路 Bellman_Ford 专题
- java 中多线程和锁的使用以及获取多线程执行结果
- touch 命令
- Codeforces Round #270 F Design Tutorial: Change the Goal 高斯消元
- PHP怎么获得当日零点的时间戳