标题: KMP算法—终于全部弄懂了 [打印本页] 作者: 杨利霞 时间: 2021-8-10 16:52 标题: KMP算法—终于全部弄懂了 KMP算法—终于全部弄懂了: R y# l" l: m4 t! W1 b
简介3 ^& I$ k6 m% b [( P6 B
KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。" G. l* N7 [% v% P) V8 K
( T1 Q1 c6 \8 z f" t# n& |
4 B( U) l6 S/ c7 Y: |9 P3 P1 t- d提取加速匹配的信息 7 i6 U# E* T7 \ 上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息! 7 Q$ ^5 s t3 {& O) h 这种信息就是对于每模式串 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 }。 9 |* }+ R2 ?$ K% v- ?: j/ q; G ; F0 S$ _, q5 f 加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的……( @1 a2 s; K0 a$ N
1 P! c7 H, W9 P4 y+ C7 l3 S先上代码2 a+ y t( ?( }. c
6 Q' i2 p( u( o3 z8 q. {3 o' _
5 z3 r$ O+ p4 b" V$ k+ W. `
void Getnext(int next[],String t) # X% B& }% ?2 q1 X7 w{, S: }! Z& m) ]3 c' ]6 }( y
int j=0,k=-1; / v3 M- g) X7 @# N3 F& v next[0]=-1; 5 V3 [$ l0 }! `. f while(j<t.length-1)) N2 Z; J+ v5 s5 Z4 d
{! F) j( {! a* J$ y) f7 Y
if(k == -1 || t[j] == t[k])* @5 G4 w" r4 S* s, r7 l8 D, l
{ 9 B4 }: V; O; j* U; T j++;k++; : R7 O4 y9 N6 J0 h$ D" Y next[j] = k;5 }) w0 k2 }, r. ^2 ^
} * n1 |$ }- [7 }% g3 X- L else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!% v; I( n7 g( j
} U) v; O+ X7 S# W. g. k1 M} * ?4 Q3 |/ C4 w( K6 P/ Y _) ?8 H1 J' J5 |, o, G
ok,下面咱们分三种情况来讲 next 的求解过程 % o1 Z4 D% ?8 e: @2 v m8 s* @, H7 q
( W S7 A$ Z$ s9 }( [2 U- J5 ^# u
特殊情况! U+ R5 f) S0 V) K
当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。7 l& @6 w( n3 i+ I& i. |& r