核心:通过寻找公共前后缀找出next数组
前后缀:
-
前缀:以第一个字母开头,但不包含最后一个字母
-
后缀:以最后一个字母结尾,但不包含第一个字母
注:若当前字符的前一位的最长公共前后缀(len)为2,则当前字符只需比较与第三位的字符是否相等,若相等则最长公共前后缀(len的长度+1;若不相等则需要与数组[len-1]位元素比较(还没搞懂)
//next数组可从两方面思考:先找出子串对应的前缀表,在将其后移一位,并将第一位填上-1
void prefix_table(char *pattern, int *prefix, int n){
prefix[0] = 0;//先将第一位的最长公共前后缀赋值为0;
int i = 1;//计数
int len = 0;
while (i < n) {
if (pattern[i] == pattern[len]) {
len++;
prefix[i] = len;
i++;
}
else {
if (len > 0) {
len = prefix[len - 1];
}
else {
prefix[i] = 0;
i++;
}
}
}
}
//简单的移位操作
void move_prefix_table(int *prefix, int n) {
for (int i = n-1; i >0 ; i--)
{
prefix[i] = prefix[i - 1];
}
prefix[0] = -1;
}
void kmp_search(char* text, char* pattern, int* prefix, int m, int n) {
int j = 0;
int i = 0;
int count = 0;
while (j<m)
{
if (i == n - 1 && text[j] == pattern[i]) {
printf("查找成功!第%d次出现的位置为:%d\n", ++count, j - i);
i = prefix[i];
}
if (text[j] == pattern[i]) {
j++;
i++;
}
else
{//若比较不相等,则将子串[前缀表[当前元素]]移动至此位置即可
i = prefix[i];
if (i == -1) {
i++;
j++;
}
}
}
}