kmp算法总结
2012-06-28 15:19
260 查看
最近看了kmp算法,经过反复的学习终于感觉完全弄懂了kmp算法,现做一个小结。
kmp算法在进行字符串匹配的时候,如果当前位置j匹配不成功,那么模式串向前移动的位数由next[j]的值决定。next数组的位置j的值表示的是模式串p中p[0~j-i]子串的前缀和后缀相匹配的最长长度,即如果next[j]=k,表示p[0~k-1]==p[j-k~j-i],而且p[k]!=p[j]。
next数组的值有三类:
-1:表示j为0或者不存在前后缀相等的子串,而且p[j]==p[0]。这个情况在匹配失效的时候,下一步应该将目标串当前位置加一和模式串的第一个位置比较
0:表示不存在前后缀相等的情况,但是p[0]!=p[j]。这个情况在匹配失效时,下一步将目标串当前比较位置与模式串的第一个位置比较(这个时候和上一个不同在于,p[0] != p[j]要求从目标串的当前位置比较)
k(k>0):表示存在最大长度为k的前缀后缀字串相匹配。这个情况下,下一步将目标串当前位置与模式串的第k+1个位置比较,即与p[k]比较。
next值的求解代码为:
kmp算法代码如下所示:
kmp算法在进行字符串匹配的时候,如果当前位置j匹配不成功,那么模式串向前移动的位数由next[j]的值决定。next数组的位置j的值表示的是模式串p中p[0~j-i]子串的前缀和后缀相匹配的最长长度,即如果next[j]=k,表示p[0~k-1]==p[j-k~j-i],而且p[k]!=p[j]。
next数组的值有三类:
-1:表示j为0或者不存在前后缀相等的子串,而且p[j]==p[0]。这个情况在匹配失效的时候,下一步应该将目标串当前位置加一和模式串的第一个位置比较
0:表示不存在前后缀相等的情况,但是p[0]!=p[j]。这个情况在匹配失效时,下一步将目标串当前比较位置与模式串的第一个位置比较(这个时候和上一个不同在于,p[0] != p[j]要求从目标串的当前位置比较)
k(k>0):表示存在最大长度为k的前缀后缀字串相匹配。这个情况下,下一步将目标串当前位置与模式串的第k+1个位置比较,即与p[k]比较。
next值的求解代码为:
void getNext(const string str,vector<int>& next) { next[0] = -1; int j = -1; for(size_t i = 0;i < str.size()-1;) { if (j == -1 || str[i] == str[j])//j表示当要计算next[i+1]时str[0...i-1]前后缀相等的子串的最长长度(-1代表没有相等的前后缀,计算next[i+1]使用了前面的信息 { ++i; ++j; if (str[i] != str[j]) next[i] = j; else next[i] = next[j]; } else j = next[j]; } }
kmp算法代码如下所示:
int kmp(const string src,const string pattern) { vector<int> next(pattern.size()); getNext(pattern,next); for (int i = 0;i < next.size();i++) cout << next[i] << " "; cout << endl; int i = 0; int j = 0; while (i < src.size() && j < pattern.size()) { if (src[i] == pattern[j]) { ++i;//注意,这里最后一次匹配成功了仍然会加一,所以在最后返回的时候不用加一 ++j; } else if (next[j] == -1) { ++i; j = 0; } else j = next[j]; } if (j >= pattern.size()) return i - pattern.size(); else return -1; }以上就是KMP算法的完整实现。要理解kmp算法,关键是理解next数组值的含义,还有next数组的求解过程。