本次程序的实现我分别用C语言和c++语言实现了一遍。
在写代码之前先说一些前置知识,kmp算法的核心我认为是求next数组的值。求next数组的值必须知道下面的这段公式,总的来说next数组的求取是根据下面的公式进行编写的。至于公式是怎么推导出来的,各种数据结构的书籍已经写的很详细了我就不叙述了。
关于怎么理解next数组的求取,其他博主写的也非常清楚了,我也不多说了。求取next的数组必须知道前缀、和后缀的概念,同时我感觉求取next数组有一点动态规划的影子。
注意:此次实现是从下标为0 的地方开始进行比较的,所以需要对公式修改,使其减一。
C语言版:
#include <stdio.h>
#include <string.h>
void get_next(char s[],int next[]);
int KMP(char s1[],char s2[],int next[]);
int main() {
int i= 0;
int next[1000];
char s2[] = "ce";
char s1[] = "ababce";
get_next(s2,next);
i=KMP(s1,s2,next);
printf("%d\n",i);
return 0;
}
void get_next(char s[],int next[])
{
int len=0;
int i=0;//后缀
int j=-1;//前缀
next[0]=-1;//第一位符前面没有前缀,由公式知设为-1.
len=strlen(s);
while(i<len)
{
if(j==-1||s[i]==s[j])
{
i++;
j++;
next[i]=j;
}
else
{
j=next[j];
}
}
}
int KMP(char s1[],char s2[],int next[])
{
int i=-1;
int j=-1;
int len1=strlen(s1);
int len2=strlen(s2);
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j>=len2)
return i-len2+1;
else
return 0;
}
C++版:
#include<iostream>
#define MAXSIZE 100
using namespace std;
typedef struct {
char ch[MAXSIZE];
int length;
}SString;
//本次程序是从下标为0开始进行比较的,所以next数组的边界需要进行改变 。
get_next(SString t,int next[]) {
int i = 0;
next[0] = -1;
int j = -1;
while(i < t.length) {
if(j == -1||t.ch[i] == t.ch[j]) {
i++;
j++;
next[i] = j;
} else {
j = next[j];
}
}
}
int kmp(SString s, SString t , int pos,int next[]) {
int i = -1,j = -1;
while(i < s.length && j < t.length) {
if(j == -1|| s.ch[i] == t.ch[j]) {
i++;
j++;
}
else {
j = next[j];
}
}
if(j >= t.length) return i-t.length+1;
else return -1;
}
int main() {
int pos = 0;
SString s,t;
int next[100];
cout<<"请输入字符主串:";
cin>>s.ch;
cout<<"\n请输入主串的长度:";
cin>>s.length;
cout<<"\n请输入子串:";
cin>>t.ch;
cout<<"\n请输入子串的长度:";
cin>>t.length;
get_next(t,next);
cout<<"子串在主串中的起始位置为:";
cout<<kmp(s,t,pos,next);
return 0;
}
经过测试代码运行是正常的。