一、简介
KMP算法,首先与BF算法做比较…….(此处略去简介200字,至于哪200字,网上随便找一篇讲KMP算法的基本上都会先讲朴素算法);
二、题外话
记得大二的时候,DS课程设计就是实现KMP算法,当时也没弄太清楚(或者弄清楚了也忘记了),就知道在网上搜到了代码,然后就好用!然而这几天抱着深入学习的态度,反而有点晕,可能年纪大了吧!在网上找到很多资料把我看的直接拔电源了都!我想说的是,根据自己这两天在网上的搜索可知,很多关于KMP算法的介绍的文章,篇幅都比较长,没有心情看下去,而且感觉不能突出重点,我只想问,有那么复杂吗?也许是优化版很多吧。那么,接下来,我们就用图标的方式,来分析一下,这个算法到底有多复杂。
三、主题
主题没有代码,只有图表。下面,我们就以
为例,我们来学习这个算法的思想。
1. 关于Next数组
什么是Next数组,Next数组时干嘛的呢?不知道?那就自己搜搜去。
这个算法的关键,就是Next数组的构造与使用,使用当然就很简单,主要的是来看看构造。
我们将KMP原始算法 与 KMP改进算法对比着来看。
原始算法:
1. Next[0] = -1:因为由失配发生时,模式串跳转的位置为:右移动j - Next[j]长度.
若在首位置失配,只能右移一位,类似朴素算法,所以要右移一位,又要将这种情况套入:j - Next[j] 因此,只能为-1。
2. Next[j] 的值为:
若存在一个k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 个字符与Next[j-k],Next[j-k+1]…Next[j-1]相等,则 Next[j] = k;
若不存在一个k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 个字符 与 Next[j-k],Next[j-k+1]…Next[j-1]相等,则 Next[j] = 0;
改进算法:
1. 1.Next[0] = -1;同上
2. .Next[j] 的值为:
若存在一个k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 个字符 与 Next[j-k],Next[j-k+1]…Next[j-1]相等,并且 Next[k] != Next[j] 则 Next[j] = k;否则若Next[k] == Next[j] 则 Next[j] = -1;
若不存在一个k,使得:模式串的前 Next[0],Next[1]... Next[k-1]) 个字符 与 Next[j-k],Next[j-k+1]…Next[j-1]相等,并且 Next[0] == Next[j] 则 Next[j] = -1;否则若Next[0] != Next[j] 则 Next[j] = 0;
根据以上原则,我们来计算一下我们的模式串的Next函数
//根据以上的图我们知道Next数组的计算了,至于代码,我就只贴一下改进算法的好了
void GetNextval(const SWORD *pswPattern, SDWORD *psdNext, SDWORD sdLength )
{
// 求模式串pswPattern的next函数值并存入数组 next。
SDWORD j = 0, k = -1;
psdNext[0] = -1;
while ( j < sdLength ) {
if ( k == -1 || pswPattern[j] == pswPattern[k] ) {
++j; ++k;
if ( pswPattern[j] != pswPattern[k] ) {
psdNext[j] = k;
}
else {
psdNext[j] = psdNext[k];
}
}
else {
k = psdNext[k];
}
}
}
OK,Next数组我们求出来了,我们再列个表格来展示一下两种算法的匹配过程吧
原始算法
改进算法:
四、结语
Sunday算法是另外一种匹配算法,据说比KMP要高效,还没学习,等以后学习了再加上吧。《算法导论》上关于KMP的内容基本上都是一些理论证明,如果数学比较好的童鞋可以看看,如果只是为了应用,那么,网上随便找到的完整代码都是可以用的了。
可能我的表述有些简单,或者哪里表述的不对,还请诸位指正,因为这两天有点懵圈了,难免有疏漏或者理解错误之处,敬请原谅。