next数组
next[j]=k
:k是当模式串中第j个字符与主串中相应字符 “失配”时,在模式串中需重新和主串中该字符进行比较的字符的位置。
$$
\left.{next[j]=}\left{\begin{array}{ll}
\mathbf{0} & \text{当 j=1 时(代表下一趟比较}\mathrm{i=i+1,j=1})\\
\mathbf{max{k\mid1<k<j}\text{且前k - 1个元素和后k-1个元素一致}}&\text{此集合不为空时,下一趟比较i = i ,j = k}\\
\mathbf{1}&\text{其它情況(即$j \ne 1且上述集合为空$)}\end{array}\right.\right.
$$
快速填写记法:
(1)字符串从1开始标号;
(2)next[1]默认为0;
(3)next[i] = 前 i -1 位字符串公共前后缀的长度 + 1;
Notice:
前缀:除最后一个字符外,一个字符串的全部头部组合;
后缀:除第一个字符外,一个字符串全部的尾部组合;所以,"aaa"
的公共前缀和长度为2。
1 2 3 4 5 6 7 8 9 10 11 12 13
| void GetNext(const char *T, int *next) { int j = 1, k = 0; next[1] = 0; while (j < strlen(T)) { if (k == 0 || T[j] == T[k]) { j++; k++; next[j] = k; } else { k = next[k]; } } }
|
nextval数组
引入原因:next数组中,前后两个相邻的字母如果相同,在匹配过程中遇到需要回退的情况,可以跳过回退到该字母。
$$
\begin{array}{l}
nextval[i] & = 1\
nextval[i] & = \left{\begin{array}{ll}
nextval[i] = nextval[next[i]] & \text{当$Pattern_i = Pattern_{next[i]}$时}\\
nextval[i] = next[i] & \text{当$Pattern_i \ne Pattern_{next[i]}$时}\end{array}\right.
\end{array}
$$

完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <stdio.h> #include <string.h>
void GetNextVal(const char *T, int *nextval) { int j = 1, k = 0; nextval[1] = 0; while (j < strlen(T)) { if (k == 0 || T[j] == T[k]) { j++; k++; if (T[j] != T[k]) { nextval[j] = k; } else { nextval[j] = nextval[k]; } } else { k = nextval[k]; } } }
int Index_KMP(const char *S, const char *T, int pos) { int nextval[100]; GetNextVal(T, nextval); int i = pos; int j = 1; printf("i\tj\n"); while (i <= strlen(S) && j <= strlen(T)) { printf("%d\t%d\n", i, j); if (j == 0 || S[i - 1] == T[j - 1]) { i++; j++; } else { j = nextval[j]; } } if (j > strlen(T)) { return i - strlen(T); } else { return 0; } }
int main() { const char S[] = "abcaacabcab"; const char T[] = "abcab"; printf("主串: %s\n", S); printf("模式串: %s\n", T); printf("匹配过程:\n"); int pos = Index_KMP(S, T, 1); if (pos > 0) { printf("匹配成功,位置: %d\n", pos); } else { printf("匹配失败\n"); } return 0; }
|