KMP算法—终于全部弄懂了/ P& S" \' r3 ^; ?& u* z
简介2 G* p0 ]9 ?; ?- r0 [$ k
KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。 , [% r1 M; V! L9 L& d7 e ! P6 u. {+ M; l. O* p) v4 i6 z3 c- H , A3 g5 l9 e% p g; A' u! X提取加速匹配的信息5 x3 }0 h1 R# t" N$ g- d
上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息!: s$ h0 Z6 n* T
这种信息就是对于每模式串 t 的每个元素 t j,都存在一个实数 k ,使得模式串 t 开头的 k 个字符(t 0 t 1…t k-1)依次与 t j 前面的 k(t j-k t j-k+1…t j-1,这里第一个字符 t j-k 最多从 t 1 开始,所以 k < j)个字符相同。如果这样的 k 有多个,则取最大的一个。模式串 t 中每个位置 j 的字符都有这种信息,采用 next 数组表示,即 next[ j ]=MAX{ k }。 7 n" A; F6 _% T5 {5 r8 L4 D + D: K Z# r0 [+ l" t. D
加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的…… p9 y: y$ Q7 z
& l9 r( x( M; t5 x9 A% S先上代码 + ?+ R& Z3 `" R A8 e 6 T/ p- R; {* N0 D) F* H m8 u. k1 ?0 ~, Z! B: Z
void Getnext(int next[],String t)2 f \' I1 j& G! Y/ _8 u8 y
{ 0 o1 a0 T: \' j+ A( a7 y int j=0,k=-1;7 N" t" [2 g' F3 c3 { _/ R
next[0]=-1;) |* ~3 P, G) u, ]' \, Z- v
while(j<t.length-1) 4 v- z8 N4 h6 p# @' ^% x {8 g: } d/ r0 Z8 ?8 D1 d
if(k == -1 || t[j] == t[k]) 3 V9 L- U% j) ]# I6 u' Q! n { 9 K; w. V6 M% |) S4 X# Y% c9 I j++;k++;. n- p# k) F+ Y1 c' K+ G
next[j] = k; ! N4 B0 C" `8 s' u# s. [7 l } 1 f7 p' ]! \; F" M3 {. S7 Y7 Y4 H else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!: ~" ^! s) z! t n+ k
}- A& Z/ W2 ~1 [9 ~+ r
}+ `/ l3 }; Y) l" _: b
4 w' `; r: I/ g5 D) k* X* E" h* m
ok,下面咱们分三种情况来讲 next 的求解过程 - f0 L' z3 s7 A, @+ T * U$ q0 d. }3 J5 ~) ?$ h1 x1 C0 M& N
特殊情况- q1 `: E$ E8 h
当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。7 v( m3 f6 T' j, `- C( x! `: m
. N6 b4 J% x3 o; n; ]
, W% x) t, P7 g, u8 j. P
当 t[j] == t[k] 的情况 6 o+ F7 }3 P$ b6 [" Y举个栗子 : \- K, V! ^; x2 t; _