字符串匹配KMP算法

问题:给定一个字符串A,要求在A中查找一个字串B。

例如,主串T=”cabcabcabcabd”,模式串P=”abcabd”

    令i,j分别指向主串和模式串中字符的位置。

    最基础的解法(BF算法),i,j置为0,每一次循环,主串从位置i开始,模式串从位置j开始,依次比较字符是否匹配,当T[i]==P[j]时,继续比较下一个字符,当T[i]!=P[j]时,i退回到i-j,即开始比较的位置+1,j退回到0,即下一次从模式串的起始位置重新开始比较。这样的时间复杂度是O(m*n)。KMP算法通过利用已知的匹配信息,可减少后面匹配的计算量。

    KMP算法先利用一个数组next存储前缀和后缀最长的相同字符个数,next[k]存储模式串P[0…k-1]中前缀和后缀最长相同的字符个数,即next[k]=q表示P[0,q-1]==P[k-q,k-1],定义next[0]=-1,例如对于模式串P=”abcabd”,next[5]=2。采用KMP算法比较字符,当T[i]!=P[j]时,由于记录了子串P[0,j-1]中前缀和后缀相同的字符数,i可以不进行回退,j回退到next[j],因为已匹配的字串P[0,j-1]中,P[j-1-next[j],j-1]与P[0,next[j]-1]相同,而P[j-1-next[j],j-1]与主串T[i-1-next[j],i-1]是匹配的,那么P[0,next[j]-1]与T[i-1-next[j],i-1]也是匹配的,所有下一次比较只需要从P[next[j]]与T[i]开始。另外,当j==0即发生不匹配的情况时,需要++i,将next[0]置为-1以考虑该情况。

求next数组

可使用递推思想来计算:

next[0]=-1,假设next[j]=k,即P[0,k-1]==P[j-k,j-1]

(1)若P[j]==P[k],那么next[j+1]=next[j]+1

2)若P[j]!=P[k],那么将问题转化为寻找与前缀相同的子串问题,利用KMP算法,k=next[k],重新开始比较。

 

代码如下

int kmpSearch(const char* pSrc, int slen, const char* patnStr, int plen)
{
	if (NULL==pSrc || NULL==patnStr || slen<=0 || plen<=0 || plen>slen)
		return -1;

	int i,j;
	int subStrIndex;
	int* nextIndexArr=new int[plen];
	GetNextIndex(patnStr,plen,nextIndexArr);
	i=0;
	j=0;
	subStrIndex=-1;
	while(i<slen)
	{
		while(i<slen && j<plen && (pSrc[i]==patnStr[j] || -1==j))
		{
			i++;
			j++;
		}
		if (j==plen)
		{
			subStrIndex=i-plen;
			break;
		}
		else
		{
			j=nextIndexArr[j];
		}
	}

	delete[] nextIndexArr;
	nextIndexArr=NULL;

	return subStrIndex;
}

void GetNextIndex(const char* pStr,int len,int* nextIndexArr)
{
	int i=0;
	nextIndexArr[0]=-1;
	int j=-1;
	while(i<len-1)
	{
		if (-1==j ||pStr[i]==pStr[j])
		{
			++i;
			++j;
			nextIndexArr[i]=j;
		}
		else
		{
			j=nextIndexArr[j];
		}
	}
}

参考资料:

http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html

http://www.matrix67.com/blog/archives/115

http://www.cppblog.com/suiaiguo/archive/2009/07/16/90237.html

http://blog.chinaunix.net/uid-27767798-id-3481340.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值