字符串匹配问题在串一章中是最需要研究的问题,结合课本理论今天花了点时间写了字符串匹配的程序,分别用爆破和简单KMP实现了,下面直接上程序:
#include <stdio.h>
#include <string.h>
#define Maxsize 100
typedef struct {
char data[Maxsize];
int length;
}string;
int bf(char test[], char main[]) { //暴破
int mlen = strlen(main);
int tlen = strlen(test);
int i,j,count = 0;
for (i = 0; i < mlen-tlen; i++) {
for (j = 0; j < tlen; j++) {
if (main[i+j] == test[j]) {
count++;
}
}
if (count == tlen) {
return i;
}
count = 0;
}
return 0;
}
void getnext(string S, int next[]) { //简单next数组获取
int head = 0;
int tail = -1;
next[0] = -1;
while (head < S.length-1) {
if ((tail == -1) || (S.data[head] == S.data[tail])) {
next[++head] = ++tail;
}
else {
tail = next[tail];
}
}
}
int kmp(char sub[], char main[],int next[]) { //KMP算法主要程序
int mlen = strlen(main);
int tlen = strlen(sub);
int i, j = 0;
for (i = 0; i < mlen; i++) {
if (main[i] == sub[j] || j == -1) {
j++;
}else{
j = next[j];
i--;
}
if (j == tlen) {
return i - j + 1;
}
}
return 0;
}
int main() {
string S;
int i;
char main[] = "abcjfascasdadasabclkabcabcakjsda";
char sub[] = "bcl";
strcpy_s(S.data, sub);
S.length = strlen(sub);
int next[20] = { 0 };
getnext(S, next);
printf("%d\n",bf(sub, main));
printf("%d",kmp(sub, main, next));
/*for (i = 0; i < S.length; i++) {
printf("%d ", next[i]);
}*/
return 0;
}
之后研究了网上的做法,发现绝大多数人都是用while来实现主要的KMP程序,但是这里我用了for循环。while更好理解而for有几处小细节需要注意,总之写程序边手写验证边写对我来说是最好的办法。
KMP算法虽然程序看上去很简单,但是其中的复杂程度不低于树图类算法,其本质就是研究子串,或者更精确讲是研究子串的next数组。结合程序我认为大家需要思考的点有:
为什么网上的做法以及书本上都将next[0]赋值为-1?
不管KMP主程序还是next数组获取,都出现类似j=next[j],tail=next[tail]这一句,他们的含义是否一样,为什么这样赋值?它和递归有什么不同?
在判断边界条件时,往往或上某个值等于0或者-1,比如kmp中的j,next数组获取程序中的tail,这是为什么?
最后需要理解也是最重要的就是next的数组中的数有几种意思,这可以帮助理解j = next[j]这种赋值的含义。
搞明白以上四个问题,才算理解了KMP算法的基本理论