KMP算法是BF算法的改良版。
#include<stdio.h>
#define MAXSIZE 30
typedef struct {
char ch[MAXSIZE + 1];
int length;
} sstring;
//新建串
void setdata(sstring *w, char data) {
w->ch[w->length] = data;
}
//显示串内元素
void appear(sstring S) {
printf("\n串内元素为:");
for (int i = 0; i < S.length; i++)
printf("%c", S.ch[i + 1]);
printf("\n串内元素有%d个\n\n", S.length);
}
//普通版
void geti(sstring T, int ival[]) {
ival[1] = 0;
ival[2] = 1;
for (int ww = 3; ww <= T.length; ww++) {
if (T.ch[ival[ww - 1]] == T.ch[ww - 1]) //比较往后新增一个字符,两个部分是否还相等
ival[ww] = ival[ww - 1] + 1; //相等的话,这里的值就比前一个加一
else //不等的话
if (T.ch[1] == T.ch[ww - 1]) //就从头开始比较,要么为2,要么为1
ival[ww] = 2;
else
ival[ww] = 1;
}
}
//修正版
//这里没有使用上面计算出的i值,而是独立成块
void getipro(sstring T, int ival[]) {
ival[1] = 0;
if(T.ch[ival[1]]==T.ch[ival[2]]) //第二个数非0即1
ival[2] = 0;
else
ival[2] = 1;
ival[0] = 1; //合理运用第一个空位,存放每个位置上的普通版的i值
//开始判断后面所有的数
for (int ww = 3; ww <= T.length; ww++) {
//承接前面已匹配到的位置,继续往后匹配
if (T.ch[ival[0]] == T.ch[ww - 1]) {
//继承成功的话,就继续判断下一个字符是否相等
if (T.ch[ival[0] + 1] == T.ch[ww])
//相等的话就左右取
ival[ww] = ival[ival[0] + 1];
else
//不等的话就上下取
ival[ww] = ival[0] + 1;
//只要继承成功,i值就会往下增
ival[0]++;
}
//当继承不了前面的值的时候,就从第一个重新开始
else if (T.ch[1] == T.ch[ww - 1]) {
printf("进入了这里");
//只要进入这里,就说明有一个字符相等了,所以说取值为2
ival[0] = 2;
if (T.ch[2] == T.ch[ww])
//相等的话就左右取
ival[ww] = ival[2];
else
ival[ww] = ival[2]+1;
}
//
else {
ival[0] = 1;
if (T.ch[1] == T.ch[ww])
ival[ww] = 0;
else
ival[ww] = 1;
}
}
}
int bmw(sstring S, sstring L, int i, int j) {
while (S.ch[i] == L.ch[j]) {
if (i <= S.length && j == L.length)
return 999;
if (i == S.length && j < L.length)
return 0;
i++;
j++;
}
return j;
}
int KMP(sstring S, sstring L, int location, int iii[]) {
int i = location, w = 1;
while (i <= S.length && w <= L.length) {
int ss = bmw(S, L, i, w);
if (ss == 999)
return i;
i++;
w = iii[ss]+1;
}
return 0;
}
void main() {
char data;
int location;
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
sstring S;
sstring L;
S.length = L.length = 0;
printf("请输入主串内的元素(以#结尾):\n");
scanf("%c", &data);
while (data != '#') {
S.length++;
setdata(&S, data);
scanf("%c", &data);
}
appear(S);
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
printf("请输入副串内的元素(以#结束):\n");
fflush(stdin);
scanf("%c", &data);
while (data != '#') {
L.length++;
setdata(&L, data);
scanf("%c", &data);
}
appear(L);
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
printf("请输入您想开始比较的位置\n");
scanf("%d", &location);
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
int iiii[MAXSIZE + 1], iii[MAXSIZE + 1]; //第一个位置空出来
geti(L, iiii);
getipro(L, iii);
int www = KMP(S, L, location, iii);
if (www)
printf("主串内含有副串,位置为:%d\n", www);
else
printf("主串内无副串。\n");
for (int ss = 1; ss <= L.length; ss++)
printf("%d\t", iiii[ss]);
printf("\n");
for (int sss = 1; sss <= L.length; sss++)
printf("%d\t", iii[sss]);
}