KMP算法的理解(二)

接上一篇KMP算法的理解(一)

我们来谈谈这个失败函数究竟他如何计算这个整型数组f[ ];

先来看看next函数:

void next(string pat,int f[ ])

{

         int len=pat.size();

         f[1]=0;

         for(int i=2;i<=len;i++)

         {

              int  j = f[i-1];

               while(pat[i]!=pat[j+1]&&j>0)

                                  j=f[j];

                if(pat[i]==pat[j+1])             f[i]=j+1;

                  else             f[i]=0;

            }

}

我们从递归的角度理解它的实现思想,然后用迭代的方式实现它的算法。给定一个模式串pat,要确定它的每一个字符的f[i],f[i]是什么,他表示模式串pat第i个字符左边最大的前后相等的字串长度,画图来说一下,首先求第i个字符的f[i]就不要考虑i的右面的字符,因此假定模式串pat为

我们现在只关心这个子串,在这个字符串里找一个前后相等的最大字串,假设找到一个最大前后相等子串长度为k(f[i]=k),在图中表示就是这里得清楚k必须是满足条件的最大子串,递归实现这一步时就是先比较p[0]p[1].........p[i-1]是否与p[1]p[2].........p[i]相等,如果相等时,则最大字串长度就为i,即f[i]=i,如果不等继续比较p[0]p[1].......p[i-2]是否与p[2]p[3]........p[i],如此不断比较,直到某一次停止找到那个最大字串k,这样f[i]就计算出来了。再多说一下为什么f[i]就是匹配失败后pat移动到的字符呢?因为它太核心了,这下我们从目标串s与模式串pat同时看,i,j匹配失败后,假设f[i]=3,即

这两组字符串相等,再联系上目标串的字符失败位置的前面均上下相等,这时将模式串pat右移一位肯定匹配失败,我们只需将pat首字符移动到图中箭头所指位置,这样就省去了没有意义的匹配,从代码实现来说就只需将模式串pat第4个字符与目标串s中当前这个失败位置匹配。如果匹配,则两个下表继续向下移动,继续匹配,如果移动后匹配失败,则继续定位f[i],到此终于说完了f[i]。

     在说它的迭代实现方法,在上面分析中先比较模式串pat:p[0]p[1].......p[i-1]与p[1]p[3]........p[i]失败,在比较p[0]p[1].......p[i-2]与p[2]p[3]........p[i],失败后继续比较p[0]p[1].......p[i-3]是否与p[3]p[4]........p[i],直到匹配成功,而在迭代中我们的实现思路是从第1个字符开始计算它的f[i],当计算f[i]是只需判断p[i]是否与p[j+1]相等,相等时只需给f[i-1]+1,然后赋值给f[i],即计算f[i]只需用到f[i-1],这也是next函数中每次for循环开始时为什么要将f[i-1]赋值给j的原因,next函数到此就理解一半了。再看看那个while循环,它其实是在确定j,因为当p[i]=p[j+1]时,f[i]=f[i-1]+1也就是f[i]=j+1,而当p[i]!=p[j+1],j又应该等于什么呢?

画图解释一下:假定f[i-1]=4;

而p[j+1]!=p[i]即p[5]!=p[i],下一个最大子串该怎么找呢?我们肯定要将前端字符减去一位,则右端字符也应该去掉一位,

如图:那么下一步就成a与b匹配,显然不匹配的,为了不做无意义的重复,该怎么办呢?我们有是用已知相等的去做,肯定有:这个相等关系,那么我们在前端中找出子串①②等于③④那①②也就等于⑦⑧,那下一步就须匹配③与i了,也就是程序中的j=f[j],然后继续重复循环等等,同时j>0,当j=0时,只需直接让f[i]=0即可。到此next函数基本就完了。

     在这KMP算法中有一种很巧妙的思想就是利用匹配过程中,已知相等的部分来将问题转化,而这个算法转化的太完美了。在函数还没开始运行,它就已经将问题转化出来,并进行求解,从而使函数在运行时就减少了许多工作,加快了算法时间。

我是第一次写博客,文中啰嗦重复地方还请大家谅解同时限于能力问题对KMP算法理解还有不足,文中不对地方,还请提出,我将及时完善文中的不足。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值