字符串匹配问题

KMP算法

         字符串比较算法中KMP算法大名鼎鼎,其主要思想是先进行预处理,对模式字串提取出一些有用的信息,然后再进行字符串比较,就可以减少比较的次数。

         而KMP的关键是对模式串的有用信息的提取,即提取什么特征值,提取出来后可以加速字符匹配的过程。

         下面举个例子来说明究竟应该提取什么特征值。

字符串:abcabaabc

模式串:abaa

序列

a

b

c

a

b

a

a

b

c

 

Index=0

a

b

a

 

 

 

 

 

 

 

Index=1

 

a

 

 

 

 

 

 

 

可用信息

Index=2

 

 

a

 

 

 

 

 

 

 

Index=3

 

 

 

a

b

a

a

 

 

 

Index=4

 

 

 

 

a

 

 

 

 

 

Index=5

 

 

 

 

 

a

b

 

 

 

         对于index=0的比较,此时ab相等,那接下去的index=1是没有必要了,可以省去了,因为前两个字符是ab是匹配的,说明序列有2个字符ab,那接下去再从模式字符串头开始匹配度的话,如果头不是a了,那么就可以跳过index=1这次,从index=2比较,故这个特征信息的关键是什么呢?

序列

a

b

c

a

b

a

a

b

c

 

Index=0

a

b

a

 

 

 

 

 

 

 

Index=1

 

a

 

 

 

 

 

 

 

可用信息

以下以一个模式串ababbaaba说明

模式串

a

b

a

b

b

a

a

b

a

0

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

2

 

 

a

 

 

 

 

 

 

3

 

 

a

b

 

 

 

 

 

4

 

 

 

 

 

 

 

 

 

5

 

 

 

 

 

a

 

 

 

6

 

 

 

 

 

 

a

 

 

7

 

 

 

 

 

 

a

b

 

8

 

 

 

 

 

 

 

 

a

         其中蓝色表示没有匹配的字符,绿色表示匹配的字符,那这就是特征信息了,以后当进行字符串匹配的时候,就可以利用预先提取的特征值了。

 

特征值的取法

以下说明两个说法

Overlay

         假设现在匹配字符串Pattern中已经匹配到了P[j-1],即P[0…j-1]都已经匹配了,但是P[j]不匹配了,

T[0]

T[1]

………..

 

T[i-j]

……

T[i-2]

T[i-1]

T[i]

 

 

 

 

 

P[0]

…..

P[j-2]

P[j-1]

P[j]

 

 

 

 

 

 

…..

P[k-2]

P[k-1]

P[k]

 

         此时如果知道了P[j-1]处于前面的P[0..k-1]都匹配,则可以直接比较P[k]和T[i]了,此时提取的模式串的特征值是:overlay[j-1]=k-1],表示P[0….k] = P[i-k…i]最大的k值,即模式串最前几个和最后几个字符相同。

 

Next

         假设现在匹配字符串Pattern中已经匹配到了P[j-1],即P[0…j-1]都已经匹配了,但是P[j]不匹配了,

T[0]

T[1]

………..

 

T[i-j]

……

T[i-2]

T[i-1]

T[i]

 

 

 

 

 

P[0]

…..

P[j-2]

P[j-1]

P[j]

 

 

 

 

 

 

…..

P[k-2]

P[k-1]

P[k]

 

         此时我们取得P[j]的特征值,即next[j]=k,表示P[j-k….j-1] = P[0…k-1],现在比较P[j]和P[k]。

 

在kmp算法中,根据取得特征值的不同,在进行字符串匹配的时候会稍有不同,具体的算法如下:

Overlay方法:

// 使用overlay方法
int kmp_find1( const char *text, const char *pattern )
{
	if ( text == NULL || pattern == NULL )
		return -1;
	int lenT = strlen(text);
	int lenP = strlen(pattern);

	int *overlay = new int[lenP];
	getOverlay( pattern, overlay );

	int i,j,s;
	i = j = 0;
	s = -1;
	while ( i<lenT && j<lenP ) {
		if ( text[i] == pattern[j] ) {
			++i;
			++j;
		}
		else {
			if ( j == 0 ) {
				++i;
			}
			else {
				j = overlay[j-1] + 1;
			}
		}
	}
	if ( j == lenP ) {
		s = i - lenP;
	}
	delete[] overlay;

	return s;
}

Next方法:

// 使用next方法
int kmp_find2( const char *text, const char *pattern )
{
	if ( text == NULL || pattern == NULL )
		return -1;
	int lenT = strlen(text);
	int lenP = strlen(pattern);

	int *next = new int[lenP];
	getNext( pattern, next );

	int i,j;
	i = j = 0;
	while ( i < lenT && j < lenP ) {
		if ( j == -1 || text[i] == pattern[j] ) {
			++i; ++j;

		}
		else {
			j = next[j];
		}
	}

	delete[] next;

	if ( j == lenP ) 
		return i - lenP;
	
	else 
		return -1;
}



你可能感兴趣的:(KMP)