KMP 算法学习总结
KMP 算法看似简单,其实想要完全理解还是有困难的。
KMP 其实可以搜索过程可以看成是一个自动机,分为 2 部分,第一部分自动机的构造 ( 对应一般的说法就是失效函数,转移函数, overlap 函数 ) ,第二部分在自动机上搜索过程。
举个例子: 目标串味 T = acabaabaabcacaabc; 模式串 P=abaabcac ;
第一步:根据模式串构造自动机
向前的箭头表示搜索前进的方向。向后的箭头表示不匹配的回溯,即失效函数,或者状态变迁函数。例如:
f(j=1) = 0;
f(j=2) = 0;
f(j=3) = 1;
f(j=4) = 1;
f(j=5) = 2;
f(j=6) = 0;
f(j=7) = 1;
假如已经构造出该自动机,那么匹配算法用伪代码描述如下:
KMP-Search :
int j = 0; // 指示当前自动机所在状态
int i; // 指示目标串匹配过程中的位置
int n; // 目标串的长度
int m; // 模式串的长度
for(i =0; i < n; i++) { // 对目标串进行匹配
for(;;) {
if( T[i] == pattern[j] ) {
j++;
if ( j == m) {
found a match ; // 找到一个匹配
j = overlap(j); // 再找下一个匹配
}
break;
}
else if( j == 0 ) break; // 如果没有与 T[i] 匹配,直接 i+1
else j = overlap(j); // 匹配了一部分出错的,根据箭头的指向回溯
}
}
接下里,就是对失效函数的构造,
KMP-Table
overlap(Pattern pattern)
{
初始化 overlap 用来存放失效函数的值 ;
overlap [0] = -1; overlap [1] = 0;
Int j = 2; // 状态机的位置
Int cnd; // 当前回溯的位置
While j < m
{
If( pattern[ j -1 ] == pattern[cnd]) // 当前匹配成功 , 移到下一个位置,
overlap [j] = cnd +1 ; cnd++; j++;
Else if( cnd > 0 ) cnd = overlap [cnd]; // cnd > 0 说明匹配了一部分后遇到不匹配, // 根据箭头方向回溯,重新匹配;
Else overlap[j] = 0; j++; // cnd = 0 说明当前不匹配
}
Return overlap
}
算法实现:
#include <iostream>
using namespace std;
/**
*KMP-Table
*input: pattern
*output : overlap[]
*/
void kmp_table(const char * P, int * overlap)
{
overlap[0] = -1;
overlap[1] = 0;
unsigned int j = 2;
int cnd = 0;
while(j < strlen(P))
{
if( P[j-1] == P[cnd])
{
overlap[j] = cnd + 1;
++j;
++cnd;
}
else if( cnd > 0)
cnd = overlap[cnd];
else
{
overlap[j] = 0;
++j;
}
}
}
/**
*KMP_Search
*input: char * Target ; char * Pattern:
*output ; the position of the Pattern in Traget;
**/
int kmp_search(const char * T, const char * P)
{
int n = strlen(T);
int m = strlen(P);
int * overlap = new int[m];
int j = 0;
kmp_table(P,overlap);
for( int k = 0; k < m; k++)
{
cout<<overlap[k]<< "" ;
}
cout<<endl;
for( int i = 0; i < n; i++)
{
for(;;)
{
if( T[i] == P[j])
{
j++;
if(j == m)
return i-m + 1 ;
break;
}
else if(j == 0) break;
else
{
j = overlap[j];
}
}
}
return -1;
}
int main()
{
char * S = "acabaabaabcacaabc";
char * W = "abaabcac";
int p = kmp_search(S,W);
cout<<"p = "<< p <<endl;
}