KMP算法——可运行版
最近在看KMP算法相关的知识,看到一篇非常不借的文章,让我在众多介绍KMP算法的博客中明白了这个算法的精髓。这个算法的思想,在这里,就不再陈述了,感兴趣的同学请参见这里。
我在本篇文章中主要将文章中代码的问题改正使之能正确运行。代码如下:
#include <iostream>
using namespace std;
/*********************************
*** get_next用来产生偏移量数组 ***
********************************/
void get_next(string t, int *next)
{
int len = t.length();
next[0] = -1;
int k = -1;
int j = 0;
while (j < len - 1)
{
// p[k]表示前缀,p[j]表示后缀
if (k == -1 || t[j] == t[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k]; // 找到之前一次更小的匹配
}
}
}
/***************************************
* Optimized get_next function
***************************************/
void get_nextval(string t, int *nextval)
{
int len = t.length();
nextval[0] = -1;
int j = 0;
int k = -1;
while (j < len - 1)
{
if (k == -1 || t[j] == t[k])
{
++k;
++j;
if (t[j] != t[k])
{
nextval[j] = k;
}
else
{
nextval[j] = nextval[k];
}
}
else
{
k = nextval[k];
}
}
}
/*********************************
* kmp_search用来从s中找出第一次
* 匹配t成功的index(从0开始)
********************************/
int kmp_search(string s, string t)
{
int i = 0;
int j = 0;
int slen = s.length();
int tlen = t.length();
int *next = new int[tlen];
//get_next(t, next);
get_nextval(t, next);
while (i < slen && j < tlen)
{
// 如果j==-1
if (j == -1)
{
i++;
j++;
}
else if (slen - i >= tlen - j)// 注意这里与原文代码不同
{
if (s[i] == t[j])
{ // 当前字符匹配成功时
i++;
j++;
}
else
{
j = next[j];
}
}
else
break;
}
if (j > 0 && j == tlen) // j>0表示不是空串
return i - j;
else
return -1; // 未匹配成功
}
int main()
{
cout << kmp_search("", "") << endl;
cout << kmp_search("bbc abcdab abcdabdcabde", "abcdabd") << endl;
return 0;
}
注意:在kmp_search中,原文中代码是 if (j == -1 || s[i] == p[j]),而这样是不对的,因为或条件的第二个条件必须在slen-i比tlen-j大的条件下成立才可对,否则不管比较结果如何都会匹配失败。