1.算法简介:KMP算法是一种利用匹配串中已和原串匹配过的信息来移动匹配串的算法。
2.设计思路:KMP算法是一种有效的的字符串匹配算法,其基本思路是利用利用匹配串已经和原串匹配过的信息来移动匹配串,而原串不回溯,从而节约匹配时间。
如上所示str2在遇到f字符之前的字符都是str1的a之前的字串。在str1中a的某个前缀k正好与str2某个字符的后缀p1匹配,那么,如果在str2中,存在某个前缀p2=p1,则将str2的下一次比较位置移动到此字符位置即可。因为,此字符的前缀p1与后缀p2相等。而p1=k,所以p2=k。即str2中此字符的前缀与str1中k是相同,不需要再比较。再次过程中,遇到str2不匹配str1的字符时,只需要回溯str2的下一次比较位置即可。
而下一次的比较位置即为某个字符之前前缀等于后缀的最长字串的长度。
字符回溯的位置用next数组。在next数组中记录的是每一个字符,其前面字串形成的前缀和后缀相等的最长长度。利用两个指针i、j,初始时,next[0]=0,i=1,j=0。当str2[i] == str2[j]时,i、j同时移动,并且next[i]=j+1。在i之前,已经可以形成的最长前缀后缀相等的字串的长度为j,此时str2[i] == str2[j],则可以在原来的基础上再增加一个长度的最长前缀后缀相等的字串。
当str2[i] != str2[j]时,重复执行j = next[j-1](在前一个已经计算的位置中寻找能够与next[i]构成相等前缀后缀的最长字串的长度),直到next[i] == next[j]或者j==0。
完成好next数组之后,即可利用next数组帮助str2去匹配str1。
3.代码:
/*KMP算法*/
#include<iostream>
#include <string.h>
using namespace std;
int main()
{
string str1 = "abeababeabf"; //原串
string str2 = "abeabf"; //匹配串
int len1 = str1.length();
int len2 = str2.length();
int next[6]; //存储匹配串中每个元素前面字串中前缀后缀相等的最长长度
//1.构建next数组
next[0] = 0;
//int j = 0;
for (int i = 1,j = 0; i < len2; i++)
{
//当str2[i] != str2[j]时,利用next数组将j回滚
while (j > 0 && str2[i] != str2[j])
{
j = next[j - 1];
}
//当str2[i] == str2[j]时,next[i]的值为j+1
if (str2[i] == str2[j])
{
j++;
}
//更新next数组
next[i] = j;
}
//2.利用next数组进行字符串匹配
for (int i = 0,j = 0; i < len1; i++)
{
while (j > 0 && str1[i] != str2[j])
{
j = next[j - 1];
}
if (str1[i] == str2[j])
{
j++;
}
if (j == len2)
{
//输出成功第一个成功匹配的字串的第一个字符在str1中的位置下标
cout << str1 << endl;
cout << str2 << endl;
cout << i - len2 + 1 << endl;
break;
}
}
return 0;
}
4.运行结果:
5.总结:KMP算法是利用了已知信息来移动匹配串,有点动态规划的感觉。KMP算法的关键是理解next数组的构建和使用。 利用KMP算法可以有效的节约字符串匹配时间,提高程序的运行速度。