KMP算法学习浅析

花了半天的来学习KMP算法,勉强算是看懂并写出来了。

看了很多大佬的解析,感觉比较舒服的就是https://www.cnblogs.com/yjiyjige/p/3263858.html的文章了

文章中有很多的插图方便大家更好的理解next数组的定义以及KMP算法的实现

next数组的每一个元素值就是当P[j] != T[i]时,j指针的下一步移动位置

这里的i和j分别为主串和模式串在匹配过程中的下标

算法思想:

1.首先初始化 :

size_t tLen = strlen(t), j = 1;//模式串指针 
       next[0] = 0;
       size_t k = 0;	       //模式串前缀指针

这里获取了模式串的长度tLen,next[0] = 0是为什么呢?

next[i]是当P[j] != T[i]时,模式串j指针的下一步移动位置

所以当p[0] != T[0]也就是第一个字符就没有匹配的情况下,比如主串“abc”,模式串“bc”

此时模式串还能怎么移,因为模式串指针已经就在开头了啊,很多其他算法将next[0]=-1,我将其赋值为0

意思是继续匹配这个位置

我听清华大学邓俊辉老师讲的时候他讲next[0] = -1称为通配符,就是可以和任何字符匹配的字符

所以当看上面的代码可以知道t<0也就是 t== -1的时候,可以直接N[++j] = ++t;

因为next[0]已经定义,所以j从1开始,不过k依然从0开始,

是因为我们要找一个模式串在当前位置的最大前缀的下标k来和相应长度的后缀匹配

2.开始遍历模式串获取next数组的值

这里比较关键的就是当t[j] != t[k]时,为什么k=next[k]???

因为当失配的时候,k就应该转移到之前匹配的位置继续匹配!!

这个很抽象,感觉可以举几个实例来理解!!!

while (j < tLen) {
	if (k == 0 || t[j] == t[k]) {
	    next[j++] = k++;
	}
	else {
	    k = next[k];
	}
}

接下来粘贴的代码是网上搜到的next数组比较简洁的代码

void GetNext(charT[],intnext[]){
  next[1]=0;
  j=1;k=0;
  while(j<T[0])
    if((k==0)||(T[j]==T[k])){
      next[++j]=++k;
  }
   else k=next[k];
}

下面的代码是我自己理解并写出来的,虽然看上去和别人写的一样。。。

void getNext(char*t, int *next) {
	size_t tLen = strlen(t), j = 1;//模式串指针 
	next[0] = 0;
	size_t k = 0;		       //前缀串指针
	while (j < tLen) {
		if (k == 0 || t[j] == t[k]) {
			next[j++] = k++;
		}
		else {
			k = next[k];
		}
	}
}

这两段代码的不同之处在于:第一段代码的T[0]位置存储了模式串T的长度,而我写的这段代码就是C语言里面的字符串数组

其他基本一样。因为我的next函数有些不同,所以我的KMP函数也有些区别!!!

int index_KMP(char *s, char *t) {
	size_t sLen = strlen(s), tLen = strlen(t);
	int i = 0, j = 0;//i为主串位置,j为模板串下标
	while (i < sLen && j < tLen) {
		if (j == 0 || s[i] == t[j]) {
			i++;
			j++;
		}
		else j = next[j];
	}
	if (j >= tLen) {
		return i - tLen;
	}
	else
	{
		return -1;
	}
}

 

测试代码和结果:

int main() {
	char s[] = "abfbcacbabcabc";
	char t[] = "abcabc";
	getNext(t, next);
	int pos = index_KMP(s, t);
	printf("模式串%s在主串%s的下标是%d\n", t, s, pos);
	system("pause");
	return 0;
}


先说这么多吧,说实话,我对这个算法的理解也比较浅,欢迎各位评论指教!!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值