字符匹配之KMP算法

                                                                                                    KMP字符串匹配算法
        该算法只与模式串(字串)有关。BF算法匹配会造成很多没有必要的回溯。kmp算法就是避免这些没有必要的回溯。
        当模式串主串匹配到某个位置的时候失配,假设该模式串下标为j,主串下标为i,则模式串下标0~j-1都是匹配的,按照BF算法,我们要将模式串回溯到首位,主串回溯到第二位重新匹配。
        情况一:
                如果模式串完全没有相同的元素,则前面匹配的全匹配,而模式串之间没有相同的元素,回溯过去也不可能匹配
                例如:
                        i l o v e T H i o v e T H K
                        i l o v e T H K
                        此时,i与Q失配,如果仅回溯一位
                        i l o v e T H i o v e T H K
                          i l o v e T H Q
                        不可能匹配,我们完全可以直接回溯到i与K来匹配
                        i l o v e T H i l o v e T H K
                                           i l o v e T H K
        情况二:
               如果模式串有相同的元素,也有不必要的回溯。
               例如:
                        w w w x h h
                        w w x
                        此时w与x失配,不能按照情况一,直接将1号元素来与失配元素匹配。而是
                        w w w x h h
                            w w x

按照KMP算法来解答:
       回溯的时候不是直接一位一位的回溯,而是按照next数组的指导来回溯。
       求next数组:
              TS串:模式串与主串失配位置前的元素就是TS串。
              TC串:TS串能自从后包含(即从后面往前看也是匹配的)TC串(TC串是TS串的字串),TC串的第一个字符是模式串的第一个字符。TC短于TS。TC可能不为1
              此时的next数组的第n个元素激素该n对应下的|TC|+1;
              注意,为了保证不丢失可能的匹配情况,必须选择最长的TC串。
                     求TC串:
                            先求出TS,分为TS1,TS2,将TS1设为主串,TS2为模式串,一步一步右移TS2,判断竖着相对应的元素是否完全相等,相等的就是最长TC串。
                            例:
                            TS1:A B A
                            TS2:    A B A
                            -->
                            TS1:A B A
                            TS2:        A B A
                            -->
                            TC=A
                            next[4]=|TC|+1=2

        C++实现源码:

#include <iostream>
#include <string>

class FstringASstring{
	public:
		std::string Fs;//主串(父串) 
		std::string Ss;//模式串 (子串) 
		int *next;
		int *nextVal;
		
		FstringASstring();
		bool KMP();
		void getNext();
		void getNextVal();
};

int main(){
	FstringASstring FAS;
	if(FAS.KMP()){
		std::cout<<"Ss是Fs的子字符串!\n";
	}else{
		std::cout<<"Ss不是Fs的子字符串!\n";
	}
	return 0;
}

FstringASstring::FstringASstring(){
	Fs="abcdefg";
	Ss="defg";
	next=new int(Ss.length());
	nextVal=new int(Ss.length());
}

void FstringASstring::getNext(){
	int indexS=0;//索引TS串中字符 
	int indexC=-1;//索引TC串中字符 
	
	next[0]=-1;
	
	while(indexS<Ss.length()-1){
		if(indexC==-1    //TC串与TS串完全没有重合,跳转到模式串的第一位去 
			//TC:1...indexC
			//TS:1...indexS
			//TC与TS最大重合了,next[indexS+1]就有结果了 
		||Ss[indexS]==Ss[indexC]){
			++indexC;
			++indexS;
			next[indexS]=indexC;
		}else{
			indexC=next[indexC];//利用已得的next,对TC串进行跳转 
		}
	}
}

bool FstringASstring::KMP(){
	getNextVal();
	int i=0;//主串下标
	int j=0;//模式串下标
	
	while(i<(int)Fs.length() && j<(int)Ss.length())
	{
		if(j==-1 || Fs[i]==Ss[j])
		{
			i++;
			j++;
		}else
		{
			j=nextVal[j];
		}
	} 
	
	if(j == (int)Ss.length())
	{
		return true;
	}
	else
	{
		return false;
	}
}

void FstringASstring::getNextVal(){
	int indexS=0;//索引TS串中字符 
	int indexC=-1;//索引TC串中字符 
	
	nextVal[0]=-1;
	
	while(indexS<Ss.length()-1){
		if(indexC==-1    //TC串与TS串完全没有重合,跳转到模式串的第一位去 
			//TC:1...indexC
			//TS:1...indexS
			//TC与TS最大重合了,next[indexS+1]就有结果了 
		||Ss[indexS]==Ss[indexC]){
			++indexC;
			++indexS;
			
			//跳转后的字符,与当前字符不同,则找最终跳转到 位置
			if(Ss[indexS]!=Ss[indexC]){
				nextVal[indexS]=indexC;
			} 
			else{
				//nextVal[indexC]已经求得了
				nextVal[indexS]=nextVal[indexC];	
			}
		}else{
			indexC=nextVal[indexC];//利用已得的next,对TC串进行跳转 
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值