KMP模式匹配算法中next[]数组求法





模式T = ″t1 t2 ⋯ tm″中的每一个字符tj 都对应一个k 值, 这个k 值仅依赖于模式本身
字符序列的构成, 而与主串无关。用next [ j]表示tj 对应的k 值( 1≤ j≤ m) , 则t1 ⋯ tk - 1 既

是t1 ⋯ tj - 1 的真前缀又是t1 ⋯ tj - 1 的真后缀的最长子串, 因此, 将k = next [ j] 称为tj 的前缀
函数值, k 就等于串t1 ⋯ tj - 1 的既是真前缀又是真后缀的最长子串的长度加1。图3 .4 给
出了一个求前缀函数值的例子。



因此, next 数组的定义如下:
next [ j] =
0 j = 1
max{ k | 1 ≤ k < j 且″t1 t2 ⋯ tk - 1″= ″tj - k + 1 tj - k + 2 ⋯ tj - 1″}
1 其他情况
由模式T 的前缀函数定义易知, next [1 ] = 0 , 因为此时t1 没有真前缀也没有真后缀。
假设已经计算出next [ 1] , next [2 ] , ⋯ , next [ j] , 如何计算next [ j + 1 ]呢? 设k= next [ j ] ,
这意味着t1 ⋯ tk - 1 既是t1 ⋯ tj - 1 的真后缀又是t1 ⋯ tj - 1 的真前缀, 即:
t1 ⋯ tk - 1 = tj - k + 1 tj - k + 2 ⋯ tj - 1
此时, 比较tk 和t j , 可能出现两种情况:
(1 ) tk = tj : 说明t1 ⋯ tk - 1 tk = tj - k + 1 ⋯ tj - 1 tj , 由前缀函数定义, next [ j] = k + 1。
(2 ) tk ≠ tj : 此时要找出t1 ⋯ tj - 1 的后缀中第2 大真前缀, 显然, 这个第2 大的真前缀
就是next [ next [ j ] ] = next [ k] , 即t1 ⋯ tnext [ k] - 1 = tj - nex t [ k] + 1 ⋯ tj - 1 (为什么?) , 再比较tnex t [ k]
和tj , 如图3 .5 所示。此时仍会出现两种情况, 当tnex t [ k] = tj 时, 与情况( 1) 类似, next [ j ] =
next [ k] + 1 ; 当tnex t [ k] ≠ tj 时, 与情况( 2) 类似, 再找t1 ⋯ tj - 1 的后缀中第3 大真前缀, 重复
(2 )的过程, 直到找到t1 ⋯ tj - 1 的后缀中的最大真前缀, 或确定t1 ⋯ tj - 1 的后缀中不存在真

前缀, 此时, next [ j + 1] = 1。



例如, 模式T = ″abaababc″的next 值计算如下:
j = 1 时, next [1 ] = 0; j = 2 时, next [ 2] = 1; j = 3 时, t1 ≠t2 , next [ 3] = 1;
j = 4 时, t1 = t3 , next [ 4] = 2;
j = 5 时, t2 ≠t4 , 令k = next [2 ] = 1 , t1 = t4 , next [5 ] = k + 1 = 2;

j = 6 时, t2 = t5 , next [ 6] = 3; j = 7 时, t3 = t6 , next [7 ] = 4 ;
j = 8 时, t4 ≠t7 , k = next [ 4] = 2 , t2 = t7 , next [ 8] = k + 1 = 3。


void GetNext ( cha r T[ ] , int next [ ] )
{
next [1] = 0;
j = 1; k = 0 ;
while ( j < T[ 0] )
if ( ( k = = 0 ) | | ( T [ j] = = T[ k] ) ) {
j ++ ;
k ++ ;
next [ j] = k ;
}
else k = next [ k] ;
}





你可能感兴趣的:(Algorithm,Interview,C/C++,kmp,算法)