对于KMP的理解,关键是在next数组的理解。
先直接给出代码,求next函数的代码如下:
void getnext()
{
int len, i,j, h;
memset(next,0, sizeof(next));
len =strlen(pat);
next[0] =-1;
i = 0; j =-1;
while (i< len) {
if (j== -1 || pat[i] == pat[j]) {
i++;
j++;
if(pat[i] != pat[j]) {
next[i]= j;
}else {
next[i]= next[j];
}
}else {
j= next[j];
}
}
return ;
}
对于函数理解:
next数组中的值的意思即为:当Pj 和 Ti不匹配了, (例1)即将模式串向前滑动,(而不是像朴素的匹配算法,i,j指针都回溯,因为Ti-j........ Ti-1 = Pi-j ........Pj-1, 对于文本串 i-j 到 i-1内容有模式串已可知)滑动的最大距离即为(设k=next[j]), 使P0...Pk-1 = Ti-k...Ti-1,所以下次直接比较 Pk 与 Ti(例2)
Ti-j ........ Ti-1 Ti 文本串
P0. ........Pj-1 Pj 模式串
例1
Ti-j ..........Ti-k........Ti-1 Ti
P0.........Pk-1 Pk
例2
那么如何求next数组?
设 next[j] = k;
由例2: Ti-k........Ti-1 = P0.........Pk-1
由例1: Ti-k........Ti-1= Pj-k ......Pj-1
所以 k 满足P0.........Pk-1 = Pj-k ......Pj-1;
(我们发现,这两个字串分别为模式串的前缀与后缀,心中先有这两个概念)
如下例:
P0 .......... Pk-1 Pk Pk+1
Pj-k ........ Pj-1 Pj Pj+1
例3
其中j-k>0,j < plen(模式串长度),按如下方法递推next[j]:
1>
若Pk = Pj, 因为next[j] = k,所以next[j+1] = k+1 = next[j] +1,因为当模式串与文本串匹配时,若在Pj+1与Ti+1处不匹配,则我们可以将模式串向前滑动,从Pk+1处继续匹配,如下例:
文本串: Ti-j ........ Ti-1 TiTi+1
模式串: P0. ........Pj-1 PjPj+1
next数组:......................k
模式串滑动:
Ti-j ..........Ti-k........Ti-1 Ti Ti+1
P0 ......... Pj-k ..... Pj-1 Pj Pj+1
P0.........Pk-1 PkPk+1 .........
我们看到,若Pk = Pj,当Pj+1 与 Ti+1不匹配,我们则应比较Pk+1与Ti+1,这还算比较显然,(其实我很讨厌看文章看到显然,其实有的时候一点也不显然,一些大牛就欺负咱们这思维不行的。这里若您没显然到,不懂,不妨自己画个图图,想想,我一开始也没一下显然到,呵呵,,,, )
但是这样却有些小问题,若Pk+1 = Pj+1,我们就不能这么干了,假设相等 Pk+1 = Pj+1,当pattern 与 text匹配时,Pj+1!= Ti+1,我们何必还要将Pk+1与Ti+1比较,我们已经知道
Pk+1 = Pj+1 != Ti+! !
所以,当Pj+1 = Pk+1,我们不能将next[j+1] = k+1,next[j+1] = next[k+1];
设 next[k+1] = h+1;
所以有 P0.... Ph = Pk-h-1 ..... Pk
又有, Pj-h.... Pj = Pk-h .... Pk
而 Pj-h... Pj = Ti-h ..... Ti
所以, P0.... Ph = Ti-h ..... Ti
所以我们直接比较Ph+1 与 Ti+1。 这就是为什么令next[j+1] = next[k+1]的原因,目的就是尽可能向前活动更大的距离。
2>
若Pk != Pj,那肯定要向前移动更大的距离,则令j = next[j] ,至于原因,自己好好思考。。。
前文已经提到了前缀与后缀,我们发现next数组所记录的值即为前缀与后缀相同的长度,可能为最长长度。
可能大家认为他就是最长长度,不是最长长度就错了。这是因为若Pk+1= Pj+1时,我们令next[j+1] = next[k+1],原因前以提到,使模式串在不匹配时,尽可能向前滑动。 如果我们总是让next[j+1] = k+1,我们求出的next数组即为当前位置前的串前缀后缀最大相同的长度。
对于next数组和KMP算法的理解,大家可以做一下以下的几个题:
poj 3461 http://poj.org/problem?id=3461
poj 2406 http://poj.org/problem?id=2406
poj 2752 http://poj.org/problem?id=2752
poj 1961 http://poj.org/problem?id=1961
hdu 3746 http://acm.hdu.edu.cn/showproblem.php?pid=3746
题目的结题报告,我会陆续写的
大家要自主完成哦 =。。=
我也感觉到了我写的不好,还请大家包涵,有什么错误,也请您指出,我还是菜鸟一个。。 希望本文能对您有所帮助