#include <iostream>
#include <string>
#include <vector>
using namespace std;
//原始next算法:
//当位置j与t的字符相同时,说明当j+1位置的模式字符与原字符串不匹配时,可以跳转到t+1来继续匹配
//因为j后连续的子串与t后一连续子串相同。
void getNext(string substr, vector<int> &next){
int j = 1,t = 0;
next[1] = 0;
while (j < substr.size()){
if (t == 0 || substr[j] == substr[t]){
next[j+1] = t + 1;
++t;
++j;
}
else
t = next[t];
}
}
//next改进方式:控制跳动位置,使匹配点匹配成功概率最大,避免重复子串导致的回溯匹配
void getNextval_1(string substr, vector<int> &nextval, vector<int> &next){
int j = 1, t = 0;
next[1] = 0;
nextval[1]=0;
while (j < substr.size()){
if (t == 0 || substr[j] == substr[t]){
next[j+1] = t + 1;
//当跳转后位置的字符不相等,则表示此处以前的位置都不可匹配 。
//否则,应向前更新跳转位置 ,排除前面的子串可匹配的可能
if (substr[j+1] != substr[next[j+1]])
nextval[j+1] = next[j+1];
else
nextval[j+1] = nextval[next[j+1]];
++j;
++t;
}
else
t = nextval[t];
}
}
//减少不必要的空间花销
void getNextval_2(string substr, vector<int> &nextval){
int j = 1, t = 0;
nextval[1]=0;
while (j < substr.size()){
if (t == 0 || substr[j] == substr[t]){
if (substr[j+1] != substr[t+1])
nextval[j+1] = t + 1;
else
nextval[j+1] = nextval[t+1];
++j;
++t;
}
else
t = nextval[t];
}
}
//O(m+k2*n)~O(m+n) : m为原串长度, n为模式串长度,k2为模式串的平均匹配次数
int KMP(string str, string substr, vector<int> next) {
int i = 1,j = 1;
while (i < str.size() && j < substr.size()){
//如果位置字符匹配,则继续向后匹配
if (j == 0 || str[i] == substr[j]) {
++i;
++j;
}
//否则,就从next[j]位置开始,继续与当前字符匹配
else {
j=next[j];
}
}
if(j>substr.size()-1)
return i - substr.size();
else
return -1;
}
int main()
{
string str,substr;
cout << "原字符串: " << endl;
cin >> str;
str = " " + str;
cout << "模式串 : " << endl;
cin >> substr;
substr = " " + substr;
vector<int> next(substr.size()+1),nextval(substr.size()+1);
getNext(substr, next);
cout << "<1>.匹配结果: " << endl;
cout << KMP(str, substr, next) << endl;
getNextval_1(substr, nextval, next);
cout << "<2>.匹配结果: " << endl;
cout << KMP(str, substr, nextval) << endl;
getNextval_2(substr, nextval);
cout << "<3>.匹配结果: " << endl;
cout << KMP(str, substr, nextval) << endl;
return 0;
}
手动实现KMP算法(C++)
于 2020-03-17 23:36:53 首次发布