一)先理解一些概念
1.写kmp之前,需要先了解:
字符的前缀与后缀 部分匹配值【这里就不说了哈】
2.利用部分匹配值,就可以做到主串不会回溯,此时
子串j需要移动 = 已匹配的字符数 - 对应的部分匹配值,表示为
move=j -next[j-1] 【看这里是next[j-1],这样写代码多麻烦,所以我们把next数组整体右移一位(这也是为什么next[0]=-1的原因)】
这样最终形式就是: j=next[ j ];
二)求next数组
求next[j+1]会有两种情况:
1.a[i]==a[j], 那么 next[j+1]=next[j]+1;
2.a[i]!=a[j],此时需要回溯,让j=next[j]后,再让a[i]与a[j]比较
见图例:
#include<iostream>
#include<string>
using namespace std;
class chars_match {
char *mainstr;
char *substr;
int* next;
int len_sub,len_main;
public:
chars_match(){}
chars_match(char mainstr[], char substr[]) {
this->len_sub=strlen(substr);
this->len_main = strlen(mainstr);//得到主串·子串的长度
this->mainstr = mainstr;
this->substr = substr;
next = new int[len_sub];
}
int kmp() {
getnext();//获取next数组
int i = 0, j = 0;
while (i < len_main && j < len_sub) {
if (j == -1 || mainstr[i] == substr[j]) {
i++; j++;
}
else {
j = next[j];
}
}
if (j >= len_sub)return i - len_sub;
else return -1;
}
void getnext() {//求next数组时也是不回溯滴!i一直往前走
int j = -1, i = 0;
next[0] = -1;
while (i < len_sub - 1) {
if (j == -1 || substr[i] == substr[j]) {
i++; j++;
next[i] = j;
}
else {
j = next[j];
}
}
}
};
int main() {
char mainstr[] = "wymlvzhanghaojieaaaabfasda";
char substr[] = "aaaab";
chars_match* kmp = new chars_match(mainstr, substr);
cout << kmp->kmp() << endl;
//int a[] = { 1,2,3,4,5 };
//int* b = a;
//cout << sizeof(b)<<sizeof(a[0]) << endl;
//cout << sizeof(a) / sizeof(*a) << endl; //这是之前写的获取数组长度的方法,感juer比较有用
return 0;
}