K nuth- M orris- P ratt 字符串查找算法,简称为 KMP算法
关于next数组的计算
先介绍概念:公共前后缀:
数组中各元素可以计算出一个公共前后缀长度,
如ABAB中的D元素,他前面有三个字符即最大前缀长度为len-1=2,所以他的最大前缀为AB,因为前缀后缀需要相等,所以此时后缀为BA,显然前后缀不相等,那么将取前缀为A,则后缀为A,此时相等则D元素的公共前后缀长度为1,类比的可以求出前面BA元素公共前后缀长度均为0,但A元素因为前面无元素了,即他的前缀为len-1=-1,所以A元素的公共前后缀长度为-1
next值即为公共前后缀长度+1
头文件
#pragma once
#pragma once
#include <stdlib.h>
#include <stdio.h>
//字符串结构体
typedef struct String
{
char* data;//数据
int len;//长度
}String;
String* initString();//获得一个String
void stringAssign(String* s, char* data);//赋值
void printString(String* s);//输出
int* getNext(String* s);//获得next值
void kmpMatch(String* master, String* sub, int* next);//执行匹配
接口实现
#include "kmp.h"
String* initString()//获得一个String
{
String* s = (String*)malloc(sizeof(String));
s->data = NULL;
s->len = 0;
}
void stringAssign(String* s, char* data)//赋值
{
//先判断s之前的data是否有值,如果有则free掉
if (s->data)
{
free(s->data);
}
int len = 0;//传递过来的串的长度
char* temp = data;//用于计算串长度
while (*temp++)
{
len++;
}
if (len == 0)
{
//即无数据
s->data = NULL;
s->len = len;
}
else
{
temp = data;//将指针指回开头
s->len = len;
s->data = (char*)malloc(sizeof(char) * (len + 1));//因为字符串以字符'\0'结尾
for (int i = 0; i < len; i++)
{
s->data[i] = *temp++;
}
}
}
void printString(String* s)//输出
{
for (int i = 0; i < s->len; i++)
{
printf((i == 0) ? "%c" : "->%c", s->data[i]);
}
printf("\n");
}
int* getNext(String* s)
{
int i = 0;//i表示索引
int j = -1;//j表示公共前后缀长度
int* next = (int*)malloc(sizeof(int) * s->len);
next[i] = j;//因为首元素的公共前后缀长度为-1
while (i < s->len - 1)//已经找到了第一个的值,所以还需要循环len-1次
{
if (j == -1 || s->data[i] == s->data[j])//j=-1说明推到了第一个元素|s->data[i] == s->data[j]成立的话
//前一个元素的公共前后缀+1即为后一个元素的公共前后缀长度
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];//再将置为-1继续循环
}
}
//for (i = 0; i < s->len; i++)
//{
// next[i] += 1;
//}
return next;//返回next数组
}
void kmpMatch(String* master, String* sub,int *next)
{
int i = 0;
int j = 0;
while (i < master->len && j < sub->len)
{
if (j == -1 || master->data[i] == sub->data[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j == sub->len)
{
printf("match success\n");
}
else
{
printf("match fail\n");
}
}
测试
#include "kmp.h"
void text()
{
String* s=initString();
String* s1=initString();
stringAssign(s, "ababacb");
stringAssign(s1, "bacb");
printString(s);
printString(s1);
int* next = getNext(s1);
for (int i = 0; i < s1->len; i++)
{
printf(i == 0 ? "%d" : "->%d", next[i]);
}
printf("\n");
kmpMatch(s, s1, next);
}
int main()
{
text();
}