KMP算法是一种高效的模式匹配算法,其最大的特点是指示主串的指针不需要回溯,整个匹配过程中,对主串仅需要从头到尾扫描一遍,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,而无需回头重读,圈复杂度可达到O(n+m)。
该算法需要对模式串进行预处理,用next[j]表示当前模式中第j个字符与主串中相应字符失配时,在模式串中需要重新和主串中该字符进行比较的字符的位置。其中“-1”表示直接与主串下一个字符比较。
以一个例子来说明。譬如给的模式串是“abcdaabcac”,经过KMP算法,可得到的next值如下表所示:
下标j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
模式串 | a | b | c | d | a | a | b | c | a | c |
next[j] | -1 | 0 | 0 | 0 | -1 | 1 | 0 | 0 | 3 | 1 |
附:
使用KMP算法查找模式串P在源串S中的位置:
/*****************************************************/class IndexKMP
{
private:
int* next; //比较字符的位置,下标从0开始
char* match;//要匹配的串,下标从0开始
int length; //要匹配的串的长度
void IniNext(); //模式串的预处理
public:
IndexKMP(char* P); //初始化,P为模式串
~IndexKMP();
int Index(char* S, int pos); //在S中查找模式串P的位置,pos为开始位置
void printNext();
};
/*****************************************************/
/*****************************************************/
#include <string.h>
#include <stdio.h>
IndexKMP::IndexKMP(char* P){
length = strlen(P);
match = new char[length];
//复制
for(int i = 0; i < length; i++)
{
match[i] = P[i];
}
next = new int[length];
IniNext();
}
IndexKMP::~IndexKMP()
{
delete[] match;
delete[] next;
}
//模式串的预处理
{
//求模式串match的next函数修正值并存入数组next。
//思路:1、从第二个字符开始与第一个字符及之后的字符进行比较,直到找到不同的字符。
//2、之后,再从该字符开始与不一致字符next值指示的字符(不一定是第一个字符)及之后的字符进行下一轮比较,依此循环。
int i = 0, j = -1, len = length - 1;next[0] = -1;
while(i < len){
if(j == -1 || match[i] == match[j]){
++i; ++j;
if(match[i] != match[j]) //对比不等,next值为不相等字符所在的位置
next[i] = j;
else next[i] = next[j]; //对比相等,则next值也相等
}
else j = next[j]; //重新开始下一轮的对比
}
}
//成功找到返回从0开始的整数,失败返回-1
int IndexKMP::Index(char* S, int pos)
{
//利用模式串match的next函数求match在主串S中第pos个字符之后的位置的KMP算法。
//其中,match非空,0<=pos<GetLength(S)。
if (pos < 0) pos = 0;
int i = pos, j = 0, len = strlen(S);
while(i < len && j < length){
if( j == -1 || S[i] == match[j])
{
++i; ++j; //继续比较后继字符
}
else j=next[j]; //模式串向右移动
}
return (j >= length) ? i-length : -1;
}
void IndexKMP::printNext()
{
for (int i = 0; i < length ; i++)
{
printf("the index of %d is %d.\n", i+1 , next[i]);
}
}
/*****************************************************/
/********************测试****************************/
void main()
{
IndexKMP test("abcdaabcac");
test.printNext();
int pos = test.Index("a12aaabaabcacwqabcdaabcacbgfrg", 0);
printf("%d\n", pos);
}
/*****************************************************/