常用写法:
下标从 0 开始
//未优化的Next数组求法
//用未优化的Next数组可以求多个模式串p在文本串s中的位置
void Get_Next() {
int len_p = strlen(p);
Next[0] = -1;
int k = -1;
int j = 0;
while (j < len_p) {
if (k == -1 || p[j] == p[k]) { //p[k]表示前缀,p[j]表示后缀
++j;
++k;
Next[j] = k;
} else {
k = Next[k];
}
}
}
//优化后的Next数组求法
//求模式串p首次出现的位置
void GetNext() {
int len_p = strlen(p);
Next[0] = -1;
int k = -1;
int j = 0;
while (j < len_p) {
if (k == -1 || p[j] == p[k]) { //p[k]表示前缀,p[j]表示后缀
++j;
++k;
if (p[j] != p[k]) {
Next[j] = k;
} else {
Next[j] = Next[k];
}
} else {
k = Next[k];
}
}
}
//匹配
int KMP() {
int i = 0;
int j = 0;
int len_s = strlen(s);
int len_p = strlen(p);
while (i < len_s && j < len_p) {
if (j == -1 || s[i] == p[j]) {
++i;
++j;
} else {
j = Next[j];
}
}
if (j == len_p) {
return (i - j);
} else {
return (-1);
}
}
其他写法:
/* https://www.cnblogs.com/SYCstudio/p/7194315.html
* KMP其他写法
*/
//求解F数组:
for (int i = 1; i < m; i++) {
int j = F[i - 1];
while ((B[j + 1] != B[i]) && (j >= 0))
j = F[j];
if (B[j + 1] == B[i])
F[i] = j + 1;
else
F[i] = -1;
}
//利用F数组寻找匹配,这里我们是每找到一个匹配就输出其开始的位置:
while (i < n) {
if (A[i] == B[j]) {
i++;
j++;
if (j == m) {
printf("%d\n", i - m + 1);//注意,这里输出的位置是从1开始标号的,如果你要输出从0开始标号的位置,应该是是i-m
j = F[j - 1] + 1;
}
} else {
if (j == 0)
i++;
else
j = F[j - 1] + 1;
}
}
//这里字符串是从 1 开始标号的
Nxt[0] = Nxt[1] = 0;
for (int i = 2, j = 0; i <= m; i++) { //构建 Next
while (j && T[j + 1] != T[i])
j = Nxt[j];
if (T[j + 1] == T[i])
++j;
Nxt[i] = j;
}
for (int i = 1, j = 0; i <= n; i++) { //匹配
while (j && T[j + 1] != S[i])
j = Nxt[j];
if (T[j + 1] == S[i])
++j;
if (j == m) { //匹配成功
Mch[i] = 1;
j = Nxt[j];
}
}