KMP算法—终于全部弄懂了6 @" X8 L2 f7 Z& d
简介 & S x Q- x' [& F8 v3 n3 H KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。 3 e* _ o3 p; d& P7 ^% g* B5 ^9 }. I- \; U) ?
! q$ Q; f7 \# l% T- E4 R
提取加速匹配的信息/ U s! y% n; z, B
上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息!+ C) \+ D8 F9 @; l. t ^/ K A4 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 }。 6 @( r4 B* x4 Q0 }+ W 7 W9 O1 ]% c$ G. {. H b( D6 M 加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的……# `: p l S. f( @% z8 P
1 T3 p O: u+ D/ d- c+ k先上代码 0 Q9 s) C7 R' I0 p2 C3 A( z# c) M4 e1 T5 G, X( W8 S
; i5 ^. V+ w; D
void Getnext(int next[],String t) / m+ f$ ]7 u3 q, J' d; i5 b$ H+ q{ * Q0 q! p% f5 q4 Z _% q int j=0,k=-1; 1 D0 d2 {, d; I% p: d4 M# m4 [4 U next[0]=-1; 7 B% z4 i% k- W5 g4 o: K, G while(j<t.length-1)! C& g$ `1 \- M6 ?, S$ W
{8 {/ T0 P1 K7 e& e- D5 B
if(k == -1 || t[j] == t[k]) . A+ H3 y/ F9 H" [$ v0 T& y/ T8 z { # @$ W6 |3 _5 x/ ]* V7 H j++;k++; 0 D- j( h5 _0 y6 @* @ q, k0 h3 Y next[j] = k; & Y; v" [$ P; Q7 k: z' P- o1 w( G } $ _& m: D- u" x P* P( i; W else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神! ' f4 @% p2 L* u; h) \3 t }* r3 q# [4 n0 I+ a9 }. V$ o' D
} % U; ?/ j; F7 a0 q8 l7 N" m+ d; H+ M& h# l
ok,下面咱们分三种情况来讲 next 的求解过程7 X! J+ V6 j& f) B7 W; z: M6 Y
& ?; V7 h$ c+ y8 T7 \, Q7 W% }! p. ~0 n6 d
特殊情况 / J+ `7 q6 N( C9 n当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。5 R3 b. [) F! b9 Y5 k9 b3 s
A. Z- `1 U9 X4 G/ U ) A6 f( ~$ A4 q, a% ^( a当 t[j] == t[k] 的情况2 `2 C" O; V$ b4 _" p
举个栗子 ) V2 E: w0 z9 F* K! c T