此文重点梳理两种最常见的next数组,以及在KMP匹配中的应用
符号说明
模式串 : T [ i ] i = 1 , . . . , T _ l e n g t h 主串 : S [ i ] i = 1 , . . . , S _ l e n g t h n e x t 数组 : n e x t [ i ] i = 1 , . . . , T _ l e n g t h 模式串:T[i] \quad i=1,...,T\_length\\ 主串:S[i] \quad i=1,...,S\_length\\ next数组:next[i]\quad i=1,...,T\_length\\ 模式串:T[i]i=1,...,T_length主串:S[i]i=1,...,S_lengthnext数组:next[i]i=1,...,T_length
第一种next数组
第一种next数组在KMP中的作用为:
当S[i]与T[j]在主串
S
[
i
]
S[i]
S[i] 处匹配失败时,将指向模式串的指针
j
j
j 跳转到模式串的
n
e
x
t
[
j
]
next[j]
next[j]处
n
e
x
t
[
j
]
=
{
0
当
j
=
1
时
M
a
x
{
k
∣
1
<
k
<
j
且“
T
1
⋯
T
k
−
1
”
=
“
T
j
−
k
−
1
⋯
T
j
−
1
”
}
当此集合不为空时
1
其他情况
next[j]=\begin{cases} 0 &当j=1时\\ Max\{k|1<k<j且“T_1 \cdots T_{k-1}”=“T_{j-k-1}\cdots T_{j-1}”\} &当此集合不为空时\\ 1 &其他情况\\ \end{cases}
next[j]=⎩
⎨
⎧0Max{k∣1<k<j且“T1⋯Tk−1”=“Tj−k−1⋯Tj−1”}1当j=1时当此集合不为空时其他情况
例1.T="aba"时next数组的计算过程
![](https://img-blog.csdnimg.cn/ee678b4d644e4c0cbca5614178553872.png)
例2.T="abaabcac"时next数组的计算过程
由于aba在上例中已计算过,从j=4开始
![](https://img-blog.csdnimg.cn/a764b31a6a814d1e9cbfd2531ce57975.png)
通过两个例子,可以将next数组的公式总结为:
- j=1时,nextj]=0成立
- 当j
≠
\neq
= 1时,扫描1~j-1,得到最长前后缀长度;next[j]=最长前后缀长度+1
(若无相等,则前后缀长度为0,next[j]=1。如例2中j=7时)
注意:前缀和后缀可重叠
练习1.
求abababaab的next数组
011234562
代码实现
void get_next(int T_length) {//模式串next数组的生成
int i = 1, j = 0;
next[1] = 0;
while (i <= T_length) {
if (j == 0 || T[i] == T[j]) {
i++;
j++;
next[i] = j;
} else
j = next[j];
}
}
在KMP中的应用
int Index_KMP(int S_length, int T_length, int pos) {//从pos开始的一次KMP匹配
int i = pos, j = 1;
while (i <= S_length && j <= T_length) {
if (j == 0 || S[i] == T[j]) {
i++;
j++;
} else
j = next[j];
}
if (j > T_length) {
printf("%d ", i - T_length);
return i - T_length;
} else return 0;//若匹配失败
}
第二种next数组
第一中next数组在KMP中的作用为:
当S[i]与T[j]匹配失败时,查询前一位 j-1 的next[j-1],跳过next[j-1]个数,从next[j-1]+1的位置开始重新匹配。
n
e
x
t
[
j
]
=
{
0
当
j
=
1
时
M
a
x
{
k
∣
1
<
k
<
j
且“
T
1
⋯
T
k
”
=
“
T
j
−
k
+
1
⋯
T
j
”
}
当此集合不为空时
0
其他情况
next[j]=\begin{cases} 0 &当j=1时\\ Max\{k|1<k<j且“T_1 \cdots T_{k}”=“T_{j-k+1}\cdots T_{j}”\} &当此集合不为空时\\ 0&其他情况\\ \end{cases}
next[j]=⎩
⎨
⎧0Max{k∣1<k<j且“T1⋯Tk”=“Tj−k+1⋯Tj”}0当j=1时当此集合不为空时其他情况
例3.T="aba"时next数组的计算过程
![](https://img-blog.csdnimg.cn/18a00ca3d6b245cbaf674cdebbb38840.png)
例4.T="abaabcac"时next数组的计算过程
由于aba在上例中已计算过,从j=4开始
![](https://img-blog.csdnimg.cn/b7e16aa8943442d9a6e9b4d5fc795431.png)
- j=1时,nextj]=0成立
- 当j
≠
\neq
= 1时,扫描1~j,得到最长前后缀长度;next[j]=最长前后缀长度
(若无相等,则前后缀长度为0,next[j]=0。如例4中j=7时)
代码实现
void get_next(int T_length) {//模式串next数组的生成
int i = 2, j = 1;
next[1] = 0;
while (i <= T_length) {
if(j==1&&T[i]!=T[j]){
next[i]=0;
i++;
}
if ( T[i] == T[j]) {
next[i] = j;
i++;
j++;
} else {
j = next[j-1] + 1;
}
}
}
在KMP中的应用
int Index_KMP(int S_length, int T_length, int pos) {//从pos开始的一次KMP匹配
int i = pos, j = 1;
while (i <= S_length && j <= T_length) {
if(j==1&&S[i]!=T[j]){
i++;
}
if (S[i] == T[j]) {
i++;
j++;
} else {
j = next[j-1] + 1;
}
}
if (j > T_length) {
printf("%d ", i - T_length - 1);
return i - T_length;
} else return 0;//若匹配失败
}
完整实现:
一:
#include<bits\stdc++.h>
#define MaxSize 10000
char T[MaxSize], S[MaxSize];
int next[MaxSize];
void get_next(int T_length) {//模式串next数组的生成
int i = 1, j = 0;
next[1] = 0;
while (i <= T_length) {
if (j == 0 || T[i] == T[j]) {
i++;
j++;
next[i] = j;
} else
j = next[j];
}
}
int Index_KMP(int S_length, int T_length, int pos) {//从pos开始的一次KMP匹配
int i = pos, j = 1;
while (i <= S_length && j <= T_length) {
if (j == 0 || S[i] == T[j]) {
i++;
j++;
} else
j = next[j];
}
if (j > T_length) {
printf("%d ", i - T_length);
return i - T_length;
} else return 0;//若匹配失败
}
int main() {
int i;
int S_length ;//主串
int T_length ;//模式串
scanf("%d", &T_length);
scanf("%s", T + 1);
scanf("%d", &S_length);
scanf("%s", S + 1);
get_next(T_length);
for (int position = 1; position < S_length; position++ ) {
position = Index_KMP(S_length, T_length, position);
if (position == 0)
break;
}
/*for (i = 1; i <= T_length-1; i++)//输出next数组
printf("%d ", next[i]);
printf("%d", next[i]);*/
return 0;
}
二:
#include<bits\stdc++.h>
#define MaxSize 10000
char T[MaxSize], S[MaxSize];
int next[MaxSize];
void get_next(int T_length) {//模式串next数组的生成
int i = 2, j = 1;
next[1] = 0;
while (i <= T_length) {
if(j==1&&T[i]!=T[j]){
next[i]=0;
i++;
}
if ( T[i] == T[j]) {
next[i] = j;
i++;
j++;
} else {
j = next[j-1] + 1;
}
}
}
int Index_KMP(int S_length, int T_length, int pos) {//从pos开始的一次KMP匹配
int i = pos, j = 1;
while (i <= S_length && j <= T_length) {
if(j==1&&S[i]!=T[j]){
i++;
}
if (S[i] == T[j]) {
i++;
j++;
} else {
j = next[j-1] + 1;
}
}
if (j > T_length) {
printf("%d ", i - T_length - 1);
return i - T_length;
} else return 0;//若匹配失败
}
int main() {
int i;
int S_length ;//主串
int T_length ;//模式串
scanf("%d", &T_length);
scanf("%s", T + 1);
scanf("%d", &S_length);
scanf("%s", S + 1);
get_next(T_length);
for (int position = 1; position < S_length; position++ ) {
position = Index_KMP(S_length, T_length, position);
if (position == 0)
break;
}
/*printf("\n");
for (i = 1; i <= T_length - 1; i++) //输出next数组
printf("%d ", next[i]);
printf("%d", next[i]);*/
return 0;
}