//对模式串进行单独的研究,找到每个位置的最长公共前后缀,以此表示需要回溯的位置
//next数组的推导, next数组的值代表发送不匹配时应该回溯到的位置
int* KMP(char* P)
{
int len = strlen(P);
int* next = (int*)malloc(sizeof(int) * len); //创建next数组
//将模式串p当成两个串(模拟主串和模式串)来用,j和k是为了错开两个串,去掉首尾而设置的下标
//是为了找到最大公共前后缀
int j = 0; //初始位置
next[0] = -1; //next数组的第0位初始化为-1,表示不存在相同的最大公共前后缀
int k = -1; //初始化位置, 设置为-1是为了错开
while (j < len)
{
//k==-1,是第一个字符,第一个字符的最大公共前后缀必然为0
if (k == -1 || P[j] == P[k]) //当P[K] == P[J]时
{
j++;
next[j] = ++k; //发生匹配时,将当前的最大公共前后缀存入next数组, 说明前j位都匹配
//所以最大长度为++k,记录下对应位置的最大公共长度
//ABDABA
//-1 0 0 0 1 2
//[0]是标志位
//next[j]是指P[0]~P[j-1]的最大公共前后缀,不含P[j]在内
}
else //当P[K] != P[J]时,回溯k到最大公共前缀的下一个位置
{
k = next[k];
}
}
return next;
}
//匹配模式串p在主串t中的位置
int pos(char* t, char* p, int* next)
{
int len_p = strlen(p);
int len_t = strlen(t);
int j = 0;
int i = 0;
for(; i < len_t && j < len_p; )
{
if (j == -1 || t[i] == p[j])
{
i++;
j++;
}
//不相等时,回溯模式串指针j
else
{
j = next[j]; //next中存的是最大公告前后缀的长度,因此如果不相等的话,只需要从
//最大公共前缀的末尾开始比较即可
}
}
//长度相等时表示完全匹配成功,j没有回溯
if (len_p <= j)
{
return i - j + 1;
}
else
{
return -1;
}
}
int main(void)
{
char* P = "aaaab";
char* T = "ABCDEABC";
int* next_arr = KMP(P);
//输出next数组
for (int i = 0; i < strlen(P); i++)
{
printf("%d ", next_arr [i]);
}
printf("\n");
printf("%d\n", pos(T, P, next_arr));
system("pause");
return 0;
}
KMP c语言
最新推荐文章于 2022-07-11 14:35:27 发布