问题描述
- 实现kmp匹配算法
- 利于软件 y-cruncher 生成百万位的 PI 的值,在其中使用kmp匹配算法匹配特定的数字串
算法描述
- kmp匹配算法实则是利用next数组优化匹配过程的匹配方法,要理解kmp匹配要了解
如何生成next数组
以及 如何使用next数组
这两个核心问题
如何生成next数组
- next数组的第 i 位其实就是从 0 到第 (i-1) 位字串的最大相同前后缀的长度值,第 0 位默认为 0
void calNextArray(const string &str, int *next)
{
int head = 0;
int tail = 1;
int len = str.length();
next[0] = 0;
while (tail < len)
{
if (str[head] == str[tail])
{
next[tail] = head + 1;
++head;
++tail;
}
else
{
if (head == 0)
{
next[tail] = 0;
++tail;
}
else
head = next[head - 1];
}
}
}
如何使用next数组
int kmp(const string &search_str, const string &match_str)
{
int *next = new int[match_str.length()];
calNextArray(match_str, next);
int searchIndex = 0;
int matchIndex = 0;
int searchLen = search_str.length();
int matchLen = match_str.length();
while (matchIndex != matchLen && searchIndex != searchLen)
{
if (search_str[searchIndex] != match_str[matchIndex])
{
if (matchIndex != 0)
matchIndex = next[matchIndex - 1];
else
++searchIndex;
}
else
{
++searchIndex;
++matchIndex;
}
}
delete[] next;
if (matchIndex != matchLen)
return -1;
else
return (searchIndex - matchIndex);
}
运行结果
- surprising!你会发现在你生成的百万位的 PI 的数字串中,如果你用6位的模式串去匹配你的支付密码,你的生日统统都在其中……(如果用人用它做字典破解你的支付密码)
![result](https://i-blog.csdnimg.cn/blog_migrate/46296225e939cf79015723d85e4078a7.png)
心得收获
- kmp算法的实质是利用模式字符串自身的特点:最大相同前后缀的值,来省去传统的
strstr()
方法匹配失败之后主串和模式串的回溯,大大加快匹配效率 - 要理解kmp算法首先要理解next数组,会求next数组
完整代码
#include <iostream>
#include <String>
#include <cstdio>
#include <cstdlib>
using namespace ::std;
void calNextArray(const string &str, int *next)
{
int head = 0;
int tail = 1;
int len = str.length();
next[0] = 0;
while (tail < len)
{
if (str[head] == str[tail])
{
next[tail] = head + 1;
++head;
++tail;
}
else
{
if (head == 0)
{
next[tail] = 0;
++tail;
}
else
head = next[head - 1];
}
}
}
int kmp(const string &search_str, const string &match_str)
{
int *next = new int[match_str.length()];
calNextArray(match_str, next);
int searchIndex = 0;
int matchIndex = 0;
int searchLen = search_str.length();
int matchLen = match_str.length();
while (matchIndex != matchLen && searchIndex != searchLen)
{
if (search_str[searchIndex] != match_str[matchIndex])
{
if (matchIndex != 0)
matchIndex = next[matchIndex - 1];
else
++searchIndex;
}
else
{
++searchIndex;
++matchIndex;
}
}
delete[] next;
if (matchIndex != matchLen)
return -1;
else
return (searchIndex - matchIndex);
}
int main()
{
cout << "************************************" << endl;
cout << "********** KMP Algorithm ************" << endl;
cout << "************************************" << endl;
cout << "Input match string:";
string match_str;
cin >> match_str;
freopen("PI.txt", "r", stdin);
string search_str;
cin >> search_str;
cout << search_str;
int location = kmp(search_str, match_str);
cout << "Match result:";
if (location == -1)
cout << "No match!" << endl;
else
cout << "Matched(" << location << ')' << endl;
return 0;
}