我对KMP的理解(浅显理解)

对于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

题目的结题报告,我会陆续写的

大家要自主完成哦 =。。=

 

我也感觉到了我写的不好,还请大家包涵,有什么错误,也请您指出,我还是菜鸟一个。。  希望本文能对您有所帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值