编程小白眼中的KMP-----C++实现
2016-01-12 20:03
375 查看
KMP起源于字符串的匹配,顾名思义匹配字符就是看2串字符是能匹配上,比如说字符串S=”abcd”字符串T=”abc”,就可以匹配上,返回的是第一个匹配的位置,也就是1。
虽然前4位一样但是第5位不一样,需要从原来的位置+1,再进行匹配。
以此类推,直到匹配为止。
求出next[]数组后,再进行匹配的时候就会加快速度。举一个求next[]数组的例子:
下面是一个KMP的实现例子。
nextval数组的求解方法是:nextval[1]=0。从第二位开始,若要求nextval[i],将next[i]的值对应的位的值与i的值进行比较(例如,第i为的值为’b’,next[i]=3,则将i的值’b’与第三位的值进行比较),若相等,nextval[i]=nextval【next[i]】(例,nextval[i]=nextval[3]);若不相等,则nextval[i]=next[i](例,nextval[i]=next[i]=3)。
1.第一位的nextval值必定为0,第二位如果与第一位相同则为0,如果不同则为1。
2.第三位的next值为1,那么将第三位和第一位进行比较,均为a,相同,则,第三位的nextval值为0。
3.第四位的next值为2,那么将第四位和第二位进行比较,不同,则第四位的nextval值为其next值,为2。
4.第五位的next值为2,那么将第五位和第二位进行比较,相同,第二位的next值为1,则继续将第二位与第一位进行比较,不同,则第五位的nextval值为第二位的next值,为1。
5.第六位的next值为3,那么将第六位和第三位进行比较,不同,则第六位的nextval值为其next值,为3。
6.第七位的next值为1,那么将第七位和第一位进行比较,相同,则第七位的nextval值为0。
7.第八位的next值为2,那么将第八位和第二位进行比较,不同,则第八位的nextval值为其next值,为2。
相应的代码只需要进行一些改进就可以了。
1、最基本的匹配。
从原字符串开始搜索,若出现不能匹配,则从原搜索位置+1继续。这样时间复杂度是很高的。虽然前4位一样但是第5位不一样,需要从原来的位置+1,再进行匹配。
以此类推,直到匹配为止。
/* 检测从主串T的pos位置开始,是否有和子串S匹配,如果有返回匹配开始位置,如果没有,返回-1 T:主串 S:子串 tlength:主串长度 slength:子串长度 pos:主串开始位置 */ int Index (char T[],char S[],int tlength,int slength,int pos) { int j=0,i=pos; while(i<tlength&&j<slength) { if(T[i]==S[j]) { i++; j++; } else { i=i-j+1; j=0; } } return j==slength?i-slength:-1; }
2、KMP匹配算法。
KMP算法就是改进了不匹配时候返回去从哪个位置开始再进行比较。比如当第一个主串的c与子串中的a不匹配时,下一次的 主串的b和子串的a(第一个)的比较可以通过分析子串的特点直接跳过这次比较。KMP算法就是为了告诉我们,我们应该每当一趟匹配过程中出现比较不等时,我们不需要回溯i指针。而是利用已经得到的“部分匹配”的结果将模式子串想右“滑动”尽可能远的距离,然后继续比较。首先先要统计一下要匹配的字符串中的重复情况,也就是求一个next[]数组。求出next[]数组后,再进行匹配的时候就会加快速度。举一个求next[]数组的例子:
下面是一个KMP的实现例子。
#include <vector> #include <string> #include <iostream> using namespace std; const vector<int> * kmp_next(string &m) { static vector<int> next(m.size()); next[0]=0; int temp; for(int i=1; i<next.size(); i++) { temp=next[i-1]; while(m[i]!=m[temp]&&temp>0) { temp=next[temp-1]; } if(m[i]==m[temp]) next[i]=temp+1; else next[i]=0; } return &next; } bool kmp_search(string text,string m,int &pos) { const vector<int> * next=kmp_next(m); int tp=0; int mp=0; for(tp=0; tp<text.size(); tp++) { while(text[tp]!=m[mp]&&mp) mp=(*next)[mp-1]; if(text[tp]==m[mp]) mp++; if(mp==m.size()) { pos=tp-mp+1; return true; } } if(tp==text.size()) return false; } int main() { int pos=0; kmp_search("abcacbc","ca",pos); cout<<"position = "<<pos+1<<endl; return 0; }
3、KMP改进算法。
KMP算法还是存在着一定的不足,比如S=”AAAABCDE”时候,T=”AAAAAX”这个时候可以求出next[]数组值为:012345,开始时i=5、j=5发现B与A不一致,j=next[5]=4。以此类推发现有多余的判断。由于T串的第2、3、4、5位置的字符和第一个位置的字符是一样的,那么可以用首位的next[1]代替相应的next[j]的值。于是对next[j]改进。nextval数组的求解方法是:nextval[1]=0。从第二位开始,若要求nextval[i],将next[i]的值对应的位的值与i的值进行比较(例如,第i为的值为’b’,next[i]=3,则将i的值’b’与第三位的值进行比较),若相等,nextval[i]=nextval【next[i]】(例,nextval[i]=nextval[3]);若不相等,则nextval[i]=next[i](例,nextval[i]=next[i]=3)。
1.第一位的nextval值必定为0,第二位如果与第一位相同则为0,如果不同则为1。
2.第三位的next值为1,那么将第三位和第一位进行比较,均为a,相同,则,第三位的nextval值为0。
3.第四位的next值为2,那么将第四位和第二位进行比较,不同,则第四位的nextval值为其next值,为2。
4.第五位的next值为2,那么将第五位和第二位进行比较,相同,第二位的next值为1,则继续将第二位与第一位进行比较,不同,则第五位的nextval值为第二位的next值,为1。
5.第六位的next值为3,那么将第六位和第三位进行比较,不同,则第六位的nextval值为其next值,为3。
6.第七位的next值为1,那么将第七位和第一位进行比较,相同,则第七位的nextval值为0。
7.第八位的next值为2,那么将第八位和第二位进行比较,不同,则第八位的nextval值为其next值,为2。
相应的代码只需要进行一些改进就可以了。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性