现总结如下:
想理解KMP算法就要先看看最原始的模式匹配























由于不必要的回溯增加了算法本身的时间复杂度,但完全不回溯就有可能漏了一个可能匹配成功的情况。
比如 : string = aaabababcaaadfe 不回溯就是这样 aaabababcaaadfe
pat = ababc //失配 ababc
所以如果完全不回溯就会漏了这个情况 aaabababcaaadfe
ababc //匹配成功
为什么会漏了那个情况呢?
其实这就是KMP研究的问题,是由于pat = ababc本身性质所决定,因为pat本身有重合的地方
那么KMP是怎么做的呢?
KMP是回溯pat串,而string串始终不回溯,这样的部分回溯就使得算法本身效率提高了很多,特别当string很长时
现在我们就可以来研究一下KMP的算法
我们想如果对于上面的例子,让j -= 2;i不变,是不是就是漏了的那种情况呢。显然这是对的,这样再继续下面的匹配函数过程,就不会有问题了。这就是KMP的算法所在。那怎么处理才知道什么时候让j减几呢?这就是KMP定义的failure function.
令P = P0P1P...Pn-1是一个模式,则其失配函数f定义为:
f(j) = i 为满足 i ="0" 如果i P0P1...Pi="Pj-iPj-i+1...Pj的最大整数"> f(j) = -1
例如,对于模式pat = abcabcacab,有:
j 0 1 2 3 4 5 6 7 8 9
pat a b c a b c a c a b
f(j) -1 -1 -1 0 1 2 3 -1 0 1
呵呵,是不是有点晕了,我看到这也晕了。没关系,继续,go ahead! Life will be better!比比先前我的那个想法,就会明白一些,也就是说,如果比较到了j = 6的位置,出现了问题,那么我们完全可以从j = 3的位置开始比较,也就是pat abcabcacab回溯了3个位置,而string当前i的位往前数3个位置肯定是abc。是不是明白了一些。
Anyhow,让我们先实现这个failure function再说




















现在再看定义了failure function有什么用
当然是得到模式匹配的规则:如果出现了形如Si-j...Si-1= P0P1...Pj-1且Si!= Pj的部分匹配,那么,若j != 0, 则下一趟模式匹配时,从失配字符Si和模式串字符Pf(j-1)+1处重新开始比较;而若j = 0时,则继续比较Si+1和P0
现在实现模式匹配算法pmatch()




































现在是不是很佩服D.E.Knuth,J.H.Morris和V.R.Pratt他们啊,其实很简单的原理,但就是他们才总结出来。
创新才是最难的!