这个字符串匹配的算法很著名,也很难理解。
研究了半天,也算看了不少博客,基本上要讲的,要理解的,各大博客大神都已详述。
我把主要几篇给我很大启迪的文章列下,也给自己往后复习留下点踪迹。
1、字符串匹配的KMP算法 http://kb.cnblogs.com/page/176818/
这篇文章,看完后很快就知道KMP算法在干什么,以及我们的核心任务是什么?
2、KMP算法的Next数组详解 http://www.cnblogs.com/tangzhengyue/p/4315393.html
这篇博客讲解的是我看的最懂的一篇。
3、KMP算法详解 http://blog.csdn.net/joylnwang/article/details/6778316
很详细,作者很厉害,不过我个人而言看的累了点,在阅读第二篇后,有节选的阅读了这篇,很受启发。next[]和f()区别,为什么要用next[]。就是下面这两段:
现在,我们来总结一下next[j]和f(j)的关系,next[j]是所有满足pattern[1…k - 1] = pattern[(j - (k - 1))…j -1](k < j),且pattern[k] != pattern[j]的k中,k的最大值。而f(j)是满足pattern[1…k - 1] = pattern[(j - (k - 1))…j -1](k < j)的k中,k的最大值。还是以上例的模式来说,对于第7个元素,其f(j) = 4, 说明pattern[7]的前3个字符与模式的前缀3相同,但是由于pattern[7] = pattern[4], 所以next[7] != 4。
通过以上这些,读者可能会有疑问,为什么不用f(j)直接作为KMP算法的跳转表呢?实际从程序正确性的角度讲是可以的,但是使用next[j]作为跳转表更加高效。还是以上面的模式为例,当target[n]与pattern[7]发生匹配失败时,根据f(j),target[n]要继续与pattern[4]进行比较。但是在计算f(8)的时候,我们会得出pattern[7] = pattern[4],所以target[n]与pattern[4]的比较也必然失败,所以target[n]与pattern[4]的比较是多余的,我们需要target[n]与更小的pattern进行比较。当然使用f(j)作为跳转表也能获得不错的性能,但是KMP三人将问题做到了极致。
4、再补充一个 http://blog.csdn.net/yutianzuijin/article/details/11954939
谢谢以上大神的博客。
自己总结了下代码,仅供参考。
int* BuildNext(string pattern)
{
int n = pattern.size();
int* next = new int[n]; //next数组存放跳转链表
int j = 0;
int k = -1;
next[0] = -1;//首位为-1
while(j < n-1)
{
if(k == -1 || pattern[j] == pattern[k])
{
if(pattern[j+1] == pattern[k+1])
{
next[++j] = next[++k];
}
else
next[++j] = ++k;
}
else
{
k = next[k];
}
}
return next;
}
int Search(string pattern,string original)
{
int *next = BuildNext(pattern);
int n = original.size();
int j = 0;
int pos = -1;//存在返回地址,不存在返回-1
for(int i = 0;i<n;i++)
{
while(j > 0 && original[i] != pattern[j])
{
j = next[j];
if(j == -1) //因为我的数组是从0开始的,所以设置初始为-1,其实还是从第一位开始比较,设置下,以防后面越界。
j = 0;
}
if(original[i] == pattern[j])
j++;
if(j == pattern.size())
{
pos = i - j+1;//此时返回的其实是最后一个匹配成功的字符串的位置。可以加break选择跳出
j = next[j-1];//数组最后一位是next[j-1]。
}
}
return pos;
}
void main()
{
string pattern = "abcabcacab";
string original = "babcbabcabcaabcabcabcacabc";
int pos = Search(pattern,original);
cout<<pos;
}