模式匹配的KMP 算法


常见的字符串匹配时,模式串长度为n,源串长度为m,则从头匹配,两个指针i指向源串,j指向模式串,如遇到不同则回溯使j=0,这样就要反复匹配会使效率变低。

因为在如今i之前 的模式串与匹配串的匹配是同样的,即回溯时,不用将模式串与源串进行匹配,而仅仅将模式串与自身匹配就可以得到其是否须要回溯以及回溯到何处。则我们能够在进行模式匹配之前,想对模式串进行自我匹配,来计算出对于i在模式串的任何位置匹配失败后回溯的位置。

而对于自身匹配的算法另一个优化的地方在于,模式串在b位置匹配到自身的a位置,然后推断一下这两个位置的字符是否同样,假设同样,则将a位置的回溯位置赋值给b,假设不同,则说明没有必要回溯到这个位置,由于回溯后不匹配,则直接将其置为0,表示从0開始又一次匹配、

失败函数的返回值为-1是用来设置其结构,使其可以在自我匹配时简单实现其功能,标识匹配失败又一次開始,但其在模式匹配中效果与0同样,都是i置为0,j++,然后继续匹配。

自我匹配放在一个失败函数中,对模式字符串进行操作,然后将结果放在一个数组中方便查询。

试着写出c++代码:


这里每次遍历时,是推断第i个字符串假设同样,那么第i加一个字符串不符就要返回的位置,每次都是对i+1进行操作,所以最后一次会对数组中下标为n的字符进行操作,会越界,则之前建fail数组时,要考虑一下。



void FailString(int f[],const char* str){
	int length = strlen(str);
	int i =0, k = -1;
	f[0] = -1;
	while( i < length){
		if(k == -1 || str[i] == str[k]){
			i++;k++;
			if(str[i] == str[k])
				f[i] = f[k];
			else
				f[i] = k;


		}else
			k = f[k];
	}
}
bool compareString(const char* charA,const char* charB){
	if( charA == 0 || charB == 0)
		return false;
	int Alen = strlen(charA);
	int Blen = strlen(charB);
	if( ! Alen || ! Blen )
		return false;
	if( Blen > Alen)return false;
	int* fail = new int[ Blen+1 ];
	FailString(fail,charB);
	int i = 0 , j = 0;
	while(i < Alen && j < Blen){
		if( charA[i] != charB[j] ){
			if(fail[i] == -1 )
				j = 0;
			else
				j = fail[i];
		}else
			j ++;
		i++;
	}
	delete[] fail;
	fail =NULL ;
	return j==Blen;
}

void main(){
	char* s1 = "abcabcaabcabbac";
	char* s2 = "abcabcabbac";
	if(compareString(s1,s2))
		cout<<"s1==s2"<<endl;
	cin.get();


}


原文地址:https://www.cnblogs.com/gcczhongduan/p/4074865.html