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++