KMP(Knuth-Morris-Pratt)字符串匹配算法是一种用于在一个文本串(text)中查找一个模式串(pattern)的高效算法。它的基本思想是利用已知信息跳过不必要的比较。
KMP 算法的核心是构建一个部分匹配表(Partial Match Table),也称为失配函数(Failure Function)。部分匹配表的作用是记录模式串中每个位置的最长公共前缀和最长公共后缀的长度。通过这个表,可以在匹配过程中根据已匹配的前缀信息来决定模式串的移动位置,从而避免重复比较。
以下是 KMP 算法的主要步骤:
1. 构建部分匹配表:对于模式串中的每个位置,计算该位置的最长公共前缀和最长公共后缀的长度。
2. 匹配过程:在文本串中按照模式串的长度移动,比较文本串和模式串对应位置的字符。当出现失配时,根据部分匹配表的信息来确定模式串应该移动的位置,而不是简单地一位一位地移动。
KMP 算法的时间复杂度为 O(m+n),其中 m 是模式串的长度,n 是文本串的长度。构建部分匹配表的时间复杂度为 O(m),匹配过程的时间复杂度为 O(n)。
KMP 算法在字符串匹配中具有广泛的应用,例如在文本编辑器中的搜索功能、数据压缩中的字符串查找等领域。相比于朴素的字符串匹配算法,KMP 算法能够显著提高匹配效率,尤其是在模式串较长或文本串较长时,优势更加明显。
以下是一个简单的 C++ 程序,演示了 KMP 算法的实现:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 构建部分匹配表
vector<int> buildPartialMatchTable(const string& pattern) {
int m = pattern.size();
vector<int> table(m, 0); // 初始化部分匹配表,默认为0
int len = 0; // 已匹配的前缀的长度
int i = 1;
while (i < m) {
if (pattern[i] == pattern[len]) {
len++;
table[i] = len;
i++;
} else {
if (len != 0) {
len = table[len - 1]; // 回退到上一个匹配的位置
} else {
table[i] = 0;
i++;
}
}
}
return table;
}
// KMP 算法实现
vector<int> kmpSearch(const string& text, const string& pattern) {
int n = text.size();
int m = pattern.size();
vector<int> result;
if (n < m) return result; // 如果文本串长度小于模式串长度,则无需匹配
vector<int> lps = buildPartialMatchTable(pattern);
int i = 0; // 文本串中的指针
int j = 0; // 模式串中的指针
while (i < n) {
if (pattern[j] == text[i]) {
i++;
j++;
}
if (j == m) {
result.push_back(i - j); // 找到匹配的位置
j = lps[j - 1]; // 回退到上一个匹配的位置,继续匹配
} else if (i < n && pattern[j] != text[i]) {
if (j != 0)
j = lps[j - 1]; // 回退到上一个匹配的位置
else
i++; // 继续匹配文本串中的下一个字符
}
}
return result;
}
int main() {
string text = "ABABDABACDABABCABAB";
string pattern = "ABABCABAB";
vector<int> matches = kmpSearch(text, pattern);
if (matches.empty()) {
cout << "Pattern not found in text." << endl;
} else {
cout << "Pattern found at positions: ";
for (int pos : matches) {
cout << pos << " ";
}
cout << endl;
}
return 0;
}
在这个程序中,buildPartialMatchTable
函数用于构建部分匹配表,kmpSearch
函数实现了 KMP 算法的匹配过程。在 main
函数中,我们演示了如何使用 KMP 算法来在文本串中查找模式串,并输出匹配的位置。
C++标准库中并没有提供类似于KMP算法那样的通用字符串匹配函数。但是,C++标准库中的 <string>
头文件提供了一些基本的字符串操作函数,例如 find()
和 find_first_of()
,可以用来进行简单的字符串匹配。
find()
函数:在字符串中查找子串第一次出现的位置,如果找到返回子串第一次出现的位置的索引,否则返回 string::npos
。
#include <iostream>
#include <string>
int main() {
std::string str = "hello world";
std::string substr = "world";
size_t found = str.find(substr);
if (found != std::string::npos) {
std::cout << "Substring found at position: " << found << std::endl;
} else {
std::cout << "Substring not found." << std::endl;
}
return 0;
}
find_first_of()
函数:在字符串中查找给定字符集中的任何字符第一次出现的位置。
#include <iostream>
#include <string>
int main() {
std::string str = "hello world";
std::string chars = "aeiou";
size_t found = str.find_first_of(chars);
if (found != std::string::npos) {
std::cout << "Vowel found at position: " << found << std::endl;
} else {
std::cout << "No vowel found." << std::endl;
}
return 0;
}
这些函数可以满足一些简单的字符串匹配需求,但如果需要更复杂的匹配功能(如正则表达式),可能需要使用第三方库(如 Boost 库)或者自行实现。