KMP算法是一种改进的字符匹配算法,具体实现是通过构造
next数组,通过next数组指示下一轮应用于进行匹配的元素位置
减少了模式串与主串的匹配次数,优化了算法的时间复杂度。
S串 主串
T串 模式匹配串
next数组的建立原理
建立一个字符串数组,字符串数组的第一个元素a[0]规定用存放
数组中含有的字符个数。
比如主串S为abaabaaab,则s[0] = 9,s[1] = 'a',s[2] = 'b',s[3] = 'a';
对于模式匹配串T为baaa,通过建立关于他的next数组可以指导模式匹配串
与主串失配时下一轮进行的字符匹配。
每个元素对应位置的next元素由其前面的字符串中,前缀和后缀匹配的个数决定
如T[1]对应的next数组元素next[1] = 0,应为他前面没有任何元素,0代表下一
轮匹配将由T[0]匹配当前主串元素。对于T[2] = a,它对应的next数组元素为1,应
为他前面没有任何前缀和后缀相匹配,前缀为b,后缀为a,所以失配时应该将T[1]
位置元素对准当前主串元素。
C语言构造next数组
void next_array(char *a,int *b) //构造next数组
{
int i,j;
b[0] = -1;
b[1] = 0;
i = 0;
j = 1;
while(j < a[0])
{
if(i == 0||a[i] == a[j])
{
i++;
j++;
b[j] = i;
}
else
i = b[i];
}
}
数组a为字符串数组,b为next数组next[0]不对应任何位置所以用-1代替。
用i和j两个游标分别代表前缀,和后缀,i的数值上等于前缀和后缀匹配的个数
,当前缀和后缀出现不匹配时,i回溯到b[i],应为b数组即next数组指导模式匹配串失配时
下一轮应该匹配的位置。
KMP算法主体
void kmp(char s[],char t[],int c[]) //kmp主体
{
int i,j,m;
int next[255]; //t串next数组
i = 1;
j = 1;
m = 0;
next_array(t,next); //构造next数组
while(i <=s[0])
{
if(s[i] == t[j] || j == 0) //匹配字符串
{
i++;
j++;
if(j == t[0]+1)
{
j = 1;
c[m] = i - t[0];
m++;
}
}
else
j = next[j];
}
}
游标i,j分别匹配主串,模式匹配串,如果匹配完成,则j重置
为1直到主串走完。将位置存入数组中。
完整代码
#include<stdio.h>
#include<malloc.h>
void create(char s[]) //创建字符串
{
int i;
printf("number of chars:\n");
scanf("%d",&s[0]);
getchar();
printf("enter chars:\n");
for(i = 1; i < s[0] + 1;i++)
{
scanf("%c",&s[i]);
}
getchar();
printf("\n");
}
void show_array(char s[]) //输出字符串
{
int i = 1;
printf("%d ",s[0]);
for(;i<s[0] + 1;i++)
{
printf("%c ",s[i]);
}
printf("\n\n");
}
void next_array(char *a,int *b) //构造next数组
{
int i,j;
b[0] = -1;
b[1] = 0;
i = 0;
j = 1;
while(j < a[0])
{
if(i == 0||a[i] == a[j])
{
i++;
j++;
b[j] = i;
}
else
i = b[i];
}
}
void kmp(char s[],char t[],int c[]) //kmp主体
{
int i,j,m;
int next[255]; //t串next数组
i = 1;
j = 1;
m = 0;
next_array(t,next); //构造next数组
while(i <=s[0])
{
if(s[i] == t[j] || j == 0) //匹配字符串
{
i++;
j++;
if(j == t[0]+1)
{
j = 1;
c[m] = i - t[0];
m++;
}
}
else
j = next[j];
}
}
int main()
{
char a[255]; //s串
int i;
int next[255]; //s串next数组
int c[255]; //存放多个匹配串位置
char t[255]; //t串
c[0] = 0; //标记是否有匹配串
printf("\n");
while(1){
printf("array S\n");
create(a); //创建s串
printf("array T\n");
create(t); //创建t串
printf("char array S\n\n");
show_array(a);
printf("char array T\n\n");
show_array(t);
printf("next array\n\n");
next_array(t,next);
for(i = 0;i<t[0]+1;i++) //显示t串next数组
printf("%d ",next[i]);
printf("\n\n");
kmp(a,t,c); //KMP
printf("KMP");
printf("\n\n");
i = 0;
if(c[i] == 0) //如果没有则错误
printf("error!");
else
while(c[i] != 0&&c[i] <= a[0]) //否则顺序输出所有匹配串位置
{
printf("%d ",c[i]);
i++;
}
printf("\n\n");
}
return 0;
}
create函数创建字符串,show_array函数打印字符串。
演示效果 编译器DEV C++