学了两天的KMP算法,总算有了自己的一点理解,写在这里做个记录了,也与各位大神交流,期待大神的指正!
AC代码:
#include <iostream>
#include <cstring>
using namespace std;
#define MaxSize 255 // 串的最大长度
// 串的定长顺序存储结构
typedef struct
{
char ch[MaxSize+1]; // 存储串的一维数组
int length; // 串的当前长度
}SString;
// 初始化
void Init(SString &S, char s[])
{
S.length = strlen(s);
for(int i = 1; i < S.length+1; i++)
{
S.ch[i] = s[i-1];
}
S.ch[0] = S.length;
}
/*
// 通过计算返回字串T的next数组值
void get_next(String T, int *next)
{
int i, j;
i = 1; j = 0;
next[1] = 0;
while (i<T.ch[0]) // 此时T[0]表示串T的长度
{
if(j == 0 || T.ch[i] == T.ch[j]) // T[i]表示后缀的单个字符, T[j]表示前缀的单个字符
{
++i;
++j;
next[i] = j;
}
else
j = next[j]; // 若字符不相同,则 j 值回溯
}
}
*/
// 求模式串T的next数组修正值并存入nextval数组
void get_nextval(SString T, int nextval[ ])
{
int i , j;
i = 1; j = 0;
nextval[1] = 0;
while (i < T.ch[0]) // 此处T[0]表示串T的长度
{
if(j == 0 || T.ch[i] == T.ch[j]) // T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
{
++i;
++j;
if(T.ch[i] != T.ch[j]) // 若当前字符与前缀字符不同
nextval[i] = j; // 则当前的 j 为nextval 在 i 位置的值
else
nextval[i] = nextval[j]; // 如果当前字符与前缀字符相同,
// 则将前缀字符的nextval 值赋值给nextval在位置 i 的值
}
else
j = nextval[j]; // 若字符不相同,则 j 值回溯
}
}
// 返回字串T在主串S中第pos 个字符之后的位置。若不存在,则返回0;
// T非空,1<=pos<=StrLength(S);
int Index_KMP(SString S, SString T, int pos)
{
int i = pos; // i 用于表示主串S当前下标值,若pos不为1,则从pos位置开始匹配
int j = 1; // j 用于表示字串T当前下标值
int nextval[255]; // 定义一next数组
get_nextval(T, nextval); // 对串T进行分析,得到nextval数组
while(i <= S.ch[0] && j <= T.ch[0]) // 当 i 小于S的长度且 j 小于T的长度时,循环继续
{
if(j == 0 || S.ch[i] == T.ch[j]) // 两字符相等则继续,与朴素算法增加了 j=0 的判断
{
++i;
++j;
}
else // 指针 j 后退,重新开始匹配
{
j = nextval[j]; // j 退回合适的位置,i 值不变
}
}
if(j > T.ch[0])
{
cout<<i - T.ch[0]<<endl;
return i - T.ch[0];
}
else
{
cout<<"匹配失败!"<<endl;
return 0;
}
}
int main()
{
SString S; SString T; int pos;
char s[MaxSize+1], t[MaxSize+1];
cout<<"请输入主串S:"<<endl;
cin>>s;
Init(S, s);
cout<<"请输入模式串T:"<<endl;
cin>>t;
Init(T, t);
cout<<"请输入你想要在S中开始匹配的位置 pos:"<<endl;
cin>>pos;
cout<<"匹配结果:";
Index_KMP(S, T, pos);
return 0;
}