KMP算法—终于全部弄懂了' H/ b% F" \9 Y1 Q! b9 @/ z* B
简介+ W2 @' n" K, l
KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。 " ^" R T. X8 u" {% q6 k6 n- E4 T$ `& ]4 X3 U2 a
2 v% @# E b: r% K; z6 T提取加速匹配的信息 ; {/ K4 R0 Y" v( ~- }9 h 上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息! ; [) N& G. g% V \ 这种信息就是对于每模式串 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 }。' c p( x, \( W9 |2 h5 `" }
* Z$ \% E$ k# m6 v: \! y, D 加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的…… 0 _5 k7 A7 A: B' | T5 s* I & j0 t9 N/ J* i3 m
先上代码 ! {) v( \* Q# Y1 b$ N; K7 W& f4 a& H3 o- E9 r& V
. q8 D) t! ?* G) D, m" d0 n: x
void Getnext(int next[],String t) ; g9 \( R% v( |0 [% S3 B{: U8 M/ Z* `& I* o5 i) A6 w
int j=0,k=-1;" A n- r4 L( Q- Z- p x$ k
next[0]=-1; 6 C7 t5 r* }, L5 V5 o7 p5 ?' n6 v6 z0 e while(j<t.length-1)1 z r5 P' Z1 x! |+ ^/ U
{ 4 b% g6 h+ p, G- X" U0 ~; D if(k == -1 || t[j] == t[k]) A" a& B1 Q& J' }" L* A1 | {6 Z; m- s) j" w4 l; H
j++;k++; 1 ]4 [" {- A& h next[j] = k;, l0 X* W! W9 A; C6 v' Z2 M
}/ N- C+ [# v+ X s/ D* p
else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神! & z! g7 d- [ W9 o8 U$ M( A" R }3 Z+ A1 ^6 V* z+ D
} 4 X5 z( z! N( h; l% m8 i6 Q6 D( `. R2 U8 q+ S# o2 o( e1 J9 g
ok,下面咱们分三种情况来讲 next 的求解过程 " l9 a; S7 ^% Y; U# G - J; ^- Q1 g4 x% N* D) u! Y9 ]0 P 5 T4 F' K; H2 | E特殊情况, e, u$ J: l" T- ?, v4 a' v
当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。 ; y& r0 z) b) C! q- s) K8 S8 u% j1 z w! g# x0 z
& N K( }/ d5 \+ s! V
当 t[j] == t[k] 的情况' R1 ?7 E$ S) U9 R0 u5 e
举个栗子 : j3 o# o8 G! o5 A( U* C( X! t5 g$ G& G