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

原创 2012年03月28日 01:05:44

先上代码:

#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了,但这种算法设计思路相当经典..


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

详细解读KMP模式匹配算法

首先我们需要了解什么是模式匹配? 子串定位运算又称为模式匹配(Pattern Matching)或串匹配(String Matching)。在串匹配中,一般将主串称为目标串,将子串称为模式串。本篇博客...

KMP模式匹配算法

KMP模式匹配算法详解(耐心看完定会理解)

 KMP模式匹配算法                       ...

kmp模式匹配算法

  • 2011-12-31 19:02
  • 291KB
  • 下载

理解KMP模式匹配算法

我自己开始写的匹配算法,

KMP模式匹配算法

kmp模式匹配算法

  • 2014-07-13 21:16
  • 1.02MB
  • 下载

KMP模式匹配算法浅析[转]

字符串匹配是计算机的基本任务之一。   举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?   许多算法可以完成这个任务...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)