字符匹配之KMP算法

KMP算法思路

1.主串不需要回滚,即i一直往后走
2.子串通过子串本身的一种性质,调整j的位置,再继续与此较
3.时间复杂度由暴力破解的O(m*n)提高到O(m+n)

子串最大重复值(这个值跟主串无关)

按元素递增分析
1.对a,没有前缀、后缀概念,匹配值为0;
2.对ab, 前缀[a],后缀[b],没有相等的值,匹配值为0;
3.对aba,前缀[a, ab],后缀[ba a],存在相同值a,长度为1,匹配值为1;
4.对abab,前缀[a, ab, aba],后缀[bab ,ab ,b ] ,存在相同值ab,长度为2;
5.对ababa, 前缀[a, ab, aba,abab],后缀[baba ,aba ,ba,a ] ,存在相同值[aba, a],最大长度为3;
6.对ababac,前缀[a, ab, aba,abab,ababa],后缀[babac ,abac ,bac,ac,c ] ,没有相等的值,匹配值为0。

现在的next数组失配时是用前一个匹配的位置找对应的j的新位置
但是算法要求是用当前位置找对应的新位置
直接将原next数组整体右移一位,next[0]定义成-1

next[j]的理解,既是表明最大前缀或后缀值,也是跳到的数组下标

1.设置j指向前缀,i遍历子串,指向后缀(其实就也是看做是主串和子串是一样的匹配过程)
2.如果p[i]== p[j]或者j == -1相等则,i++;j++; next[i] =j (再次注意,j是下标的同时,还是最大前缀值)
3.如果p[i]!= p[j], j = next[j] ;如果p[j]与p[i]还是不相等,继续循环跳next[j]

在这里插入图片描述
匹配过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
匹配完成

#include<stdio.h>
#include<string.h>
#define p_len 6	//模式串最长度

void getNext(const char p[],int next[]){
	int i=1;			
	int j=0;			//j表示next[]的值
	int len=strlen(p);	//模式串长度
	next[0]=-1;			//next数组首位为-1,代表右移一位
	next[1]=0;
	while(i<len-1){
		if(j == -1 || p[i] == p[j]){
		/*如果前一个字符,和next[j]所指向的位置(j)的字符相等,则j+1*/
			next[++i] = (++j);	
		}else {
			j = next[j];	//否则j回查next[j]值所指向的字符位置的j值
		}
	}
}

int kmp(char str[],char p[]){
	int i=0 ,j=0;
	int m=strlen(str);
	int n=strlen(p);
	int next[p_len];
	getNext(p,next);
	for(i=0;i<m;++i){
		while(j > -1 && str[i] != p[j]){
			j = next[j];	//如果本轮没找到则退出
		}
		if(j == -1 || str[i] == p[j]){
			++j;
		}
		if(j == n)	return i-j+1;	//匹配成功返回主串位置
	}
	return -1;		//匹配不成功
}

int main(void){
	char str[]="ababsabcabecbc";
	char p[]="abcabe";
	int next[p_len],i,result;
	getNext(p,next);
	for(i=0;i<p_len;i++)
		printf("%4d",next[i]);
	result=kmp(str,p);
	if(result == -1)
		printf("\ndon't find\n");
	else
		printf("\nfind location %d\n",result);
	getchar();
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值