kmp 算法的一种代码实现
本文档仅提供代码实现,有注释,但由于 kmp 算法理解的困难性,深入理解可能还需参考一些其他资料。
源码如下
#include<iostream>
//简单匹配
int index(std::string&, std::string&);
// next[]
void get_next(std::string&, int next[]);
// 优化后 nextval[]
void get_nextval(std::string&, int next[]);
// kmp 算法
int kmp(std::string&, std::string&);
// 主函数
int main() {
std::string s1{ "daabaabcabajkfajlaj" }, s2{ "abaabcaba" };
std::cout << "测试串:" << s1 << '\n';
std::cout << "模式串:" << s2 << std::endl;
std::cout << "简单匹配得出匹配下标:" << index(s1, s2) << '\n';
std::cout << "kmp 算法匹配得出匹配下标:" << kmp(s1, s2) << '\n' << std::endl;
system("pause");
return 0;
}
// 简单匹配
int index(std::string& Str, std::string& str) {
if (str.length() > Str.length()) return 0;
// i 为主串 Str 下标,j 为子串 str 下标,k 为每次匹配开始位置
size_t i = 0, j = 0, k = 0;
while (i < Str.length() && j < str.size()) {
if (Str[i] == str[j]) {
++i; ++j;
}
else {
j = 0;
// 匹配失败,将主串 i 挪到下一位再开始比较
i = ++k;
}
}
if (j >= str.size() - 1) // 注意这一步的判断
return k;
else return -1;
}
// next[]
void get_next(std::string& str, int next[]) {
int i = 0, j = -1;
next[0] = -1;
while (i < str.size()) {
if (j == -1 || str[i] == str[j]) {
++i; ++j;
next[i] = j;
}
else j = next[j]; // 回退
}
}
// 优化后 nextval[]
void get_nextval(std::string& str, int next[]) {
int i = 0, j = -1;
next[0] = -1;
while (i < str.size()) {
if (j == -1 || str[i] == str[j]) {
++i; ++j;
if (str[i] != str[j]) next[i] = j;
else next[i] = next[j];
}
else j = next[j]; // 回退
}
}
// kmp 算法
int kmp(std::string& str, std::string& substr) {
const int size = 100;
int next[size];
get_next(substr, next);
// get_nextval(substr, next);
// 打印 next 数组
std::cout << "next 数组:\n";
for (size_t i = 0; i < substr.size(); ++i) {
std::cout << next[i] << ' ';
}
std::cout << std::endl;
int i = 0, j = 0;
int sublen = substr.size(); // 这里要注意有符号和无符号的比较!!!
std::cout << "kmp 时模式串下标j的变化\n";
while (i < str.size() && j < sublen) {
if (j == -1 || str[i] == substr[j]) {
++i; ++j;
}
else {
// 失败,模式串右移
j = next[j];
}
std::cout << "j = " << j << ' ';
}
std::cout << std::endl;
if (j >= substr.size())
return i - substr.length();
else return -1;
}