字符串匹配(朴素查询+简单KMP)

字符串匹配问题在串一章中是最需要研究的问题,结合课本理论今天花了点时间写了字符串匹配的程序,分别用爆破和简单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算法的基本理论

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值