1. 原理分析
| a | b | a | a | b | c | a | c | d |
|---|---|---|---|---|---|---|---|---|
| a | b | a | c |
i = 3, j = 3
- 用 i 表示匹配数组的下标
- 用 j 表示被匹配模板数组的下标
- 当 i 能一一匹配时,i++
- 当 i 不能匹配时,不后退 i,根据 next 数组中的值(记录要移动到的位置)来更改 j
| a | b | a | a | b | c | a | c | d |
|---|---|---|---|---|---|---|---|---|
| a | b | a | c |
i = 3, j = 1
- 继续对比 i 和 j 对应的值
- 若不匹配,继续根据 next 数组中的值来更改 j
| a | b | a | a | b | c | a | c | d |
|---|---|---|---|---|---|---|---|---|
| a | b | a | c |
i = 3, j = 0
- 若 i 和 j 还是不匹配,则 i 前进一格
2. next 数组代码原理
next 数组是根据模板数组的内容之间的关系而确立的
设 b = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'a', 'c']
则 next[0] = [-1], next[1] = 0,
next[2] 根据 b[0] 和 b[1] 来确定, b[0] != b[1], 故 next[2] = 0
next[3] 根据 b[0] 和 b[2] 来确定, b[0] != b[2], 故 next[3] = 0
next[4] 根据 b[0] 和 b[next3] 来确定, b[0] == b[3], 故 next[4] = 1,
且后面要从 b[next[4]](1) 作为比较值
next[5] 根据 b[1] 和 b[4] 来确定, b[1] == b[4], 故 next[5] = 2
next[6] 根据 b[2] 和 b[5] 来确定, b[2] == b[5], 故 next[5] = 3
next[7] 根据 b[3] 和 b[6] 来确定, b[3] == b[6], 故 next[5] = 4
next[8] 根据 b[4] 和 b[7] 来确定, b[4] != b[7],
则说明长链 abcaa 断掉, 故新链要满足……ax(……a 与 next[4] 的链要能匹配, a-x 为比较的项,
可不同,当不同时则再继续断链,直到没找到匹配链),
在 next[4] 中的匹配链为 ab(b0b1), 故 b[7] 跟 b[2](b[b[4]])进行匹配;
b[7] != b[2], 且 next[2] 中没有匹配链,则找 next[0], 故 next[8] = 0;
// 算法实现:
// P为结构体,里面包含 str 字符串和 length 长度
void getNext(Strs *P, int next[])
{
int i = 1;
int j = 0;
next[0] = -1;
next[1] = 0;
while(i < P->length-1){
if(P->str[i] == P->str[j]){
i++;
j++;
next[i] = j;
}else if(j == 0){
next[i+1] = 0;
}else{
j = next[j];
}
}
}
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct STRS{
char t[50];
int length;
}Strs;
void getNext(int *, Strs *);
int KMPindex(Strs *, Strs *, int *);
int main(){
Strs *string1, *string2;
int next[10], pos;
string1 = (Strs *)malloc(sizeof(Strs));
string2 = (Strs *)malloc(sizeof(Strs));
printf("请输入主串\n");
scanf("%s", string1->t);
string1->length = strlen(string1->t);
printf("请输入子串\n");
scanf("%s", string2->t);
string2->length = strlen(string2->t);
getNext(next, string2);
pos = KMPindex(string1, string2, next);
if(pos){
printf("%d", pos);
}else{
printf("不存在");
}
return 0;
}
void getNext(int *next, Strs *string)
{
int i=1, j=0;
next[0] = -1;
next[1] = 0;
while(i<string->length)
{
if(string->t[i] == string->t[j])
{
i++;
j++;
next[i] = j;
}else if(j == 0)
i++;
else
j = next[j];
}
}
int KMPindex(Strs *string1, Strs *string2, int *next)
{
int i=0, j=0;
while(i < string1->length && j < string2->length)
{
if(string1->t[i] == string2->t[j]){
i++;
j++;
}else if(j == 0){
i++;
}else{
j = next[j];
}
}
if(j == string2->length)
return i-string2->length;
return -1;
}