KMP模式匹配算法的一些理解

先上代码:

#include <string>
using namespace std;
/****************************KMP模式匹配算法****************************/
void setIndexOfNext(const string &AnalyzeThis, int *Next){//AnalyzeThis, Next从0开始存储有效数据..
	const int Num = AnalyzeThis.size() -  1;
	int preChar = -1, posChar = 0;
	Next[0] = -1;
	while(posChar < Num){
		if(preChar == -1 || AnalyzeThis[preChar] == AnalyzeThis[posChar]){
			++preChar;
			++posChar;
			Next[posChar] = preChar;
		}
		else
			preChar = Next[preChar];	
	}
}

int First_Index_of(const string &Text, const string &Key, int i){//i用来定位Text的字符
	int Next[300];
	int temIndexOfKey = 0;
	setIndexOfNext(Key, Next);
	const int Num_Text = Text.size();
	const int Num_Key = Key.size();
	while(i < Num_Text && temIndexOfKey < Num_Key){
		if(temIndexOfKey == -1 || Text[i] == Key[temIndexOfKey]){
			++i;
			++temIndexOfKey;			
		}
		else
			temIndexOfKey = Next[temIndexOfKey];
	}
	if(temIndexOfKey == Key.size())//结束时i指向符合单词的最后一个字母所在的下标的后一位
		return i - Key.size();
	else
		return -1;
}

/****************************KMP模式匹配算法优化版****************************/
void better_setIndexOfNext(const string &AnalyzeThis, int *Next){//AnalyzeThis, Next从0开始存储有效数据..
	const int Num = AnalyzeThis.size() -  1;
	int preChar = -1, posChar = 0;
	Next[0] = -1;
	while(posChar < Num){
		if(preChar == -1 || AnalyzeThis[preChar] == AnalyzeThis[posChar]){
			++preChar;
			++posChar;
			if(AnalyzeThis[preChar] != AnalyzeThis[posChar])
				Next[posChar] = preChar;
			else
				Next[posChar] = Next[preChar];//再次去掉多余的比较..
		}
		else
			preChar = Next[preChar];	
	}
}

int better_First_Index_of(const string &Text, const string &Key, int i){//i用来定位Text的字符
	int Next[300];
	int temIndexOfKey = 0;
	better_setIndexOfNext(Key, Next);
	const int Num_Text = Text.size();
	const int Num_Key = Key.size();
	while(i < Num_Text && temIndexOfKey < Num_Key){
		if(temIndexOfKey == -1 || Text[i] == Key[temIndexOfKey]){
			++i;
			++temIndexOfKey;			
		}
		else
			temIndexOfKey = Next[temIndexOfKey];
	}
	if(temIndexOfKey == Key.size())//结束时i指向符合单词的最后一个字母所在的下标的后一位
		return i - Key.size();
	else
		return -1;
}

KMP算法的精髓在于:建立匹配串的模式数组(Next[])

1. 什么是Next数组?

传统的字符串匹配采用的是最简单最二逼的迭代,这必然会造成大量不必要的操作,Next数组的存在就是为了去除这些不必要的操作。
每一个Next数组的下标都映射了一个匹配串(AnalyzeThis)中具有相同下标的元素,当这个元素与主串(Text)的某个元素(设为a)不匹配的时候,
Next立功的时候就到了:
它会告诉这个傻逼的电脑,应该继续从匹配串(AnalyzeThis)的哪个元素开始继续与a进行匹配工作。



2. Next数组的建立原理与数值意义

如前文所述,Next充当的是一个指挥着的角色。

这个是Next数组的定义:




(这是第一个元素) || ======================|| =(这货就是传说中的第K个元素) ===============....(1)
===============================|| ========================||   =(这个是第J个元素) ============....(2)

如上面图所示,这两行表示的是同一串字符,为编译理解我将它表述为两行。其中第一行红色部分指代 字符串P1 ...Pk-1
,第二行红色部分指代 字符串Pj-k+1......Pj-1, 他俩相等。

相信看到这里大家都清楚了。因为 Next[J]被使用的前提是,匹配串(Key)的J元素的前面所有元素都与主串某区域匹配,但主串的a元素与匹配串中K元素不匹配。
即等价于(2)的红色部分( 字符串Pj-k+1......Pj-1)与主串相同区域匹配,即等价于(1)中的红色部分( 字符串P1 ...Pk-1
与主串的相同区域匹配,又因为这是一个最大的字串(参照上面的MAX定义),所以我只要继续比较匹配串中的K元素与主串中的a元素即可。

Next[J] = K  的原理如上所示~


再来看实现的代码:


while(posChar < Num){
	if(preChar == -1 || AnalyzeThis[preChar] == AnalyzeThis[posChar]){
		++preChar;
		++posChar;
		Next[posChar] = preChar;
	}
	else
		preChar = Next[preChar];
}

这货的主要思想是,1. 将 AnalyzeThis[preChar] == AnalyzeThis[posChar] 的关系表达在第 posChar + 1个元素上,而这种关系又与 posChar + 1上的元素无关!这是一个不断重复的过程..2. 通过 preChar = Next[preChar] 回溯,找到先前一个较短的串,再进行比较..

PS: KMP已经OUT了,但这种算法设计思路相当经典..


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值