模式匹配的Brute-Force算法和KMP算法

模式匹配

模式匹配的具体含义是在主串s中从start开始查找一个与模式串t相同的子串。如果找到则返回模式串t的第一个字符在主串中的下标;如果未找到则返回-1。

 

1.模式匹配的Brute-Force算法

Brute-Force算法实现模式匹配的思想是:从主串s=”s0s1…sn-1”的第一个字符开始和模式串t=”t0t1…tn-1”的第一个字符比较,若相等,则继续比较后续字符;否则从主串s的第二个字符开始重新与模式串t的第一个字符比较。如此不断继续,若存在模式串中的每个字符依次和主串中的一个连续字符序列相等,则匹配成功,返回模式串t的第一个字符在主串中的下标;否则匹配失败,返回-1。

int Index_BF ( char S [ ], char T [ ], int pos )
{
	/* 若串 S 中从第pos(S 的下标0≤pos<StrLength(S))个字符
	起存在和串 T 相同的子串,则称匹配成功,返回第一个
	这样的子串在串 S 中的下标,否则返回 -1    */

	int i = pos, j = 0;
	
	while ( S[i+j] != '\0'&& T[j] != '\0')
		if ( S[i+j] == T[j] )
			j ++; // 继续比较后一字符
		else
		{
			i ++; j = 0; // 重新开始新的一轮匹配
		}
		
	if ( T[j] == '\0')
		return i; // 匹配成功   返回下标
	else
		return -1; // 串S中(第pos个字符起)不存在和串T相同的子串
} // Index_BF

 

 

2.模式匹配的 KMP 算法

KMP 算法的思想是:设s为主串,t为模式串,设i为主串s当前比较字符的下标,j为模式串t当前比较字符的下标,另i和j的初值为0. 当si= tj时,i和j分别增1再继续比较;否则i不变,j改变为等于next[j],再继续比较。依次类推,直到下列两种情况之一:一种是j退回到某个j = next[j] 时有si = tj;则i和j分别增1再继续比较;另一种是j退回到j = -1,此时令主串和模式串的下标各增1(此时模式串下标便退回0:j = j + 1 = -1 + 1 = 0),再继续比较。

 

其中,我们把模式串中从第一个字符开始到任一个字符为止的模式串中的真子串定义为next[j]函数,则next[j]函数定义为:

①next[j]= max{ k | 0<k<j 且“t0t1…tk-1” = “tj-ktj-k+1…tj-1”}     当此集合非空时

②next[j]= 0                                         其他情况

③next[j]= -1                                        当 j = 0 时

若模式串t中存在真子串“t0t1…tk-1” = “tj-ktj-k+1…tj-1”,且满足0<k<j,则next[j]表示当模式串t中的tj与主串s的si比较不相等时,模式串t中需重新和主串s的si比较的字符下标为k,即下一次开始比较si和tk;若模式串t中不存在如上所说的真子串,有next[j] = 0,则下一次开始比较si和t0;当j = 0时,令next[j] = -1,此处-1为一标记,表示下一次开始比较si+1和t0.

 

简而言之,KMP算法对Brute-Force算法的改进就是利用已经得到的部分匹配结果将模式串t右滑一段距离再继续比较,从而无需回退主串s的下标值。

 

#include <iostream>
#include <string>
using namespace std;

void get_nextval(const char *T, int next[])
{
	// 求模式串T的next函数值并存入数组 next
	int j = 0, k = -1;
	next[0] = -1;
	
	while ( T[j] != '\0' )
	{
		if (k == -1 || T[j] == T[k])
		{
			++j;
			++k;
			next[j] = k;
		}// if
		else
			k = next[k];
	}// while
	
	////这里是我加的显示部分
	// for(int  i=0;i<j;i++)
	//{
	//     cout<<next[i];
	//}
	//cout<<endl;

}// get_nextval 

int KMP(const char *Text,const char* Pattern)
{
	if( !Text||!Pattern||  Pattern[0]=='\0'  ||  Text[0]=='\0' )
		return -1;//空指针或空串,返回-1

	int len=0;
	const char * c=Pattern;
	
	while(*c++!='\0')//计算模式串长度
	{
		++len;
	}
	
	int *next=new int[len+1];
	get_nextval(Pattern,next);//求Pattern的next函数值
	
	int index=0,i=0,j=0;
	while(Text[i]!='\0'  && Pattern[j]!='\0' )
	{
		if(Text[i]== Pattern[j])
		{
			++i;// 继续比较后继字符
			++j;
		}
		else
		{
			index += j-next[j];
			if(next[j]!=-1)
				j=next[j];// 模式串向右移动
			else
			{
				j=0;
				++i;
			}
		}
	}//while
	
	delete []next;
	if(Pattern[j]=='\0')
		return index;// 匹配成功
	else
		return -1;
}

int main()//abCabCad
{
	char* text="bababCabCadcaabcaababcbaaaabaaacababcaabc";
	char*pattern="abCabCad";
	
	cout<<KMP(text,pattern)<<endl;
	return 0;
}

 

参考资料:

1.《数据结构——使用C++语言(第二版)》 朱战立 编著

2.MeChecksV的博文:http://www.cnblogs.com/mechecksv/articles/473300.html

posted @ 2010-08-10 15:59  MikeLin  阅读(5747)  评论(0)    收藏  举报