KMP 字符串的匹配算法

一、KMP算法与Brute-force算法的最大区别就在于KMP算法在比较时,主串的指针i不用回溯,只需回溯字串的指针j

而Brute-force算法就是简单的从第一个字符比到最后一位,这时需要对主串的i进行回溯,这样算法的比较次数明显增多

KMP的算法复杂度可为O(m +n)而Brute-force的算法复杂度可为O(m*n)。

二、在做KMP时我们可以知道每一次字串j的回溯,即每一次字串后移的位数等于匹配的位数减去部分匹配的位数

即可以得到一公式   移位数 = 匹配位数 - 部分匹配位数

如何得到部分匹配位数呢?

这是由字串的前缀与后缀的最大共同的字符串决定的。如ABDAB这是部分匹配位数为2

三、如何推算next[]呢?

由特殊到一般:

    假设:有next[j]= k,即“t[0]...............t[k-1]”=''t[j-k]................t[j-1]'',0<k<j,此时next[j+1]有两种情况

          字串:

             t = t[0].........t[j-k]......t[j-1].......t[j]......t[m-1]

                           t' = t[0].......t[k-1]      t[k]

                              t' =t[0]....................t[k']

if(t[k] == t[j]) {
         next[j+1] = next[j] +1 = next[k] +1;

}
//此时我们就需从字串t'中找到t' 等于t[k]的情况
else if(t[k ] != t[j]){
         next[j+1]  = k'+1= next[k]+1;

}
//如果没找到则k = 0
else{
          next[j+1] = 0;
}

//以上代码只是分析使用的是伪码。

KMP代码:

/**
*KMP 字符串匹配算法核心是GetNext[]这一步,要知道在j>1时不匹配应该保证i不变,获取next[j]的值
*由字符串的比较我们可以知道我们可以保证i不变来做比较,i是不用回溯的只需回溯j的值就 可以了
*/

#include <iostream>
#include <windows.h>
#include <string.h>
using namespace std;
typedef struct{
      char str[100];
	  int length ;
}KMPString;


/**
*字符串的比较
*@param S,start ,T,next分别表示主串,开始比较的位置,字串以及next[j]的值
*@return 返回成功匹配后的v值表示成功的第一次出现的下标,如果匹配失败返回-1; 
*/
int KMPIndex(KMPString S,int start,KMPString T,int next[]){
	cout<<"字串:"<<endl;
	for(int i = 0;i <T.length;i++){
		      cout<<T.str[i];
	}
	cout<<endl;
	cout<<"主串:"<<endl;
	for(int i = 0;i <S.length;i++){
		      cout<<S.str[i];
	}
	cout<<endl;
	  int i = start;
	  int j = 0;
	  int count = 0;
	  int num = 0;
	  int v ;
	  while(i <S.length && j <T.length){
	      if(S.str[i] == T.str[j]){
			    count++;
		        i++;
			    j++;
		  }
		  else if(j == 0){
			  i++;
		  }else{
			    num++;
		        j = next[j];
		  }
	  }
		  if(j == T.length){
			  cout<<"匹配成功!"<<endl;
		         v = i-T.length;
		  }else{
			  cout<<"匹配失败!"<<endl;
		         v = -1;
		  }
		   cout <<"count="<<count<<" "<<"num = " <<num<<endl;
	      return v;
	      
	  
	 


}


//获取next[j]
void GetNext(KMPString T,int next[]){
	//  cout<<T<<endl;
	    int j = 1;
		int k = 0;
		next[0] = 0;
		next[1] = 0;
		cout<<"T长度:"<<T.length <<endl;
		for(int i = 0;i <T.length;i++){
		      cout<<T.str[i]<<endl;
		}
		while(j < T.length){
			cout<<"第"<<j<<"次进入while循环"<<endl;
			if(T.str[j] == T.str[k]){
			     next[j+1] = k+1;
				 j++;
				 k++;
			
			}else if(k == 0){//这里是个出口,在循环后没有找到真串时,下一步跳回第一步也就是j 回溯到0
				 cout<<"进入k ==0"<<endl;
			     next[j+1] = 0;
				 j++;
			}else{//这里可以不断的获取到真串的存在,如果存在next[j]下一步调到j = k
				cout<<" k = next[k]"<<endl;
			    k = next[k];
			
			}
		
		
		}
		for(int i = 0;i <T.length;i++){
		      cout<<"next["<<i<<"]="<<next[i]<<endl;
		}
		      cout<<"k="<<k<<endl;
		


}
//main函数

int main(){


	KMPString  S = {{"aaaaaaaab"},9},T = {{"aaaab"},5};
	//KMPString  S = {{"aaaaaaaa"},8},T = {{"aaaab"},5};
	int next[100] ={0,1,2,3};
	int count = 0 ;
	int pos =0;
	cout<<"获取GetNext[j]"<<endl;
	GetNext(T,next);
	cout<<"获取next成功!"<<endl;
	pos = KMPIndex(S,0,T,next);
	if(pos >= 0){
	       cout<<"获取到匹配成功的位置!"<<endl;
           cout<<"匹配成功的位置:"<<pos<<endl;
		   for(int i = pos ;i <S.length;i++){
		         cout<<S.str[i];
		   }
		   cout<<endl;
	}
	  system("PAUSE");
      return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值