KMP算法的理解着实花了不少时间,幸好网上前辈的博客写得都相当好,结合几篇博客仔细想想还是可以理解的,这里仅做一下整理。
KMP算法概念理解看这篇博客就够了字符串匹配的KMP算法by阮一峰
主要的逻辑那篇博客都有讲,求出next数组,进行简单的加减即可完成匹配。至于求解next数组,则是KMP算法的关键也是难点所在。
需参考以下两篇博客:
1、http://www.cnblogs.com/c-cloud/p/3224788.html
2、http://www.cnblogs.com/10jschen/archive/2012/08/21/2648451.html
第一篇的博主提出的求对称性的思想非常利于理解,逻辑上证明了next数组用于匹配字符串的可行性。
第二篇博主要介绍了next数组的求解算法以及配图,特此摘录一下重点部分。
代码实现
1 void makeNext(const char P[],int next[])
2 {
3 int q,k;//q:模版字符串下标;k:最大前后缀长度
4 int m = strlen(P);//模版字符串长度
5 next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0
6 for (q = 1,k = 0; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
7 {
8 while(k > 0 && P[q] != P[k])//递归的求出P[0]···P[q]的最大的相同的前后缀长度k
9 k = next[k-1]; //不理解没关系看下面的分析,这个while循环是整段代码的精髓所在,确实不好理解
10 if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1
11 {
12 k++;
13 }
14 next[q] = k;
15 }
16}
对于其中的while循环:
1、已知前一步计算时最大相同的前后缀长度为k(k>0),即P[0]···P[k-1];
2、此时比较第k项P[k]与P[q],如图1所示
3、如果P[K]等于P[q],那么很简单跳出while循环;
4、关键!关键有木有!关键如果不等呢???那么我们应该利用已经得到的next[0]···next[k-1]来求P[0]···P[k-1]这个子串中最大相同前后缀,可能有同学要问了——为什么要求P[0]···P[k-1]的最大相同前后缀呢???是啊!为什么呢? 原因在于P[k]已经和P[q]失配了,而且P[q-k] ··· P[q-1]又与P[0] ···P[k-1]相同,看来P[0]···P[k-1]这么长的子串是用不了了,那么我要找个同样也是P[0]打头、P[k-1]结尾的子串即P[0]···Pj-1,看看它的下一项P[j]是否能和P[q]匹配。如图2所示
其中的图2便是理解while循环中k = next[k-1];这一步的关键。