字符串匹配算法kmp

关于kmp算法:本人参考了很多博客和书籍,没找到很好的方法去理解它。

被搜索字符串T:ababdaababcd

需要查找的字符串P:ababc

kmp算法的next数组,首先它是储存的字符串P中的相应位置之前的前缀和后缀中前缀和后缀匹配的最大缀字符串的长度。

例如:

P字符串中: a b a b c 下标分别是0,1,2,3,4

在下标为0时,即P[0]=a,在P[0]前面没有字符串,故其没有前缀和后缀。

在下标为1时,即P[1]=b,在P[1]前面有P[0],但是只有P[0],故没有前缀和后缀

在下标为2时,即P[2]=a,在P[2]前面有ab,故子字符串为:ab,前缀分别是a,b没有相同的前缀和后缀。

依次类推:

P[3]的前面的字符串为:aba,前缀为,a,ab.后缀为:a,ba。相同的前缀后缀为a.

P[4]的前面的字符串为:abab,前缀为,a,ab,aba.后缀为:b,ab,bab。相同的前缀后缀为ab.

故可得next数组为

-1,0,0,1,2

现在我们得到了next数组。但是next数组怎么用,思想是什么呢?

假设:我们匹配P[j+1]和T[i+j+1]的时候匹配不成功了。//下表从0算,i表示第i次循环T字符串匹配

T[i+j+1]和p[j+1]不匹配了

如果P[j+1]之前没有相同的前缀和后缀,

那么直接进行下次循环匹配T[i+1+j+1]和P[0]匹配一个个匹配。//退回到暴力匹配。

如果有相同的前缀和后缀呢?

假设P[j]之前的相同的前缀后缀的长度为x,j=x+m+x+1;//m表示相同的前缀和后缀之间的字符串长度

那么也就是说T[i+x+m+x+1]和P[x+m+x+1]不匹配

但是T[i+x+m+x]和P[x+m+x]是匹配的.

我们这时候就只需要在T[i+x+m+x+1]处即T[i+j+1]和P[x+1]匹配了不用回溯P到P[0].//也就是前缀的后一位开始匹配

因为T[x+m]到T[x+m+x]处正好是的前缀P[0]到P[x],这是我们已经匹配过的信息。

例如:P=ababc匹配到T=ababdaababcd是P[4]和T[4]时不匹配了//i=0

next数组中记录P的next[4]为2,相同的缀长度为2.

此时j=2+0+2+1;//m=0,x=2

故下次匹配T[4]和P[2]处。//P[2]就是前缀ab的后一位.

这就是P字符串next数组的用处所在。

代码参考的数据结构,周彦军,王玉茹,关伟洲版。

代码如下:

#include <stdio.h>
#include <string.h>
typedef struct  st_StrType StrType; 
struct  st_StrType {
	int length;
	char	ch[1024];
};
int	next[50];

void GetNext( StrType P, int next[ ] ) {
	int j = 0, k =- 1;
	next[ 0] =- 1;
 while ( j< P. length- 1) 
 {
 	
 	if(( k ==- 1)||( P. ch[ k]== P. ch[ j]))
 	{ 
 		k++;
 		j++;
 		next[ j] = k;
 		
 	} 
 	else 
	{	
	 		k = next[ k];
	}	
	printf("next[%d]=%d \n",j,next[j]);
}
//printf("\n");
}

int KMPSearch( StrType T, StrType P, int pos) {
	 int i = pos, j = 0; 
	 while ( ( i< T. length) && ( j< P. length) ) 
	 if (( j ==- 1) || (T. ch[ i] == P. ch[ j])) 
	 	{ 
	 		i++; 
	 		j++;
	 	}
	 	else  
	 		j = next[ j]; 
	 if ( j >= P. length) 
	 	 		return i- P. length;  
	 		else
	 		  return - 1; 
 }



int main(void)
{
	StrType test,test1;
	test.length=12;
	test1.length=5;
	memcpy(test.ch,"ababdaababcd",12);
  memcpy(test1.ch,"ababc",5);
	
	GetNext(test1,next);
	printf("%d \n",KMPSearch(test,test1,1));
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值