KMP算法
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键在于:每当一次匹配过程中出现比较不等时,不需回溯i指针,而是利用已经匹配得到的“部分匹配”的结果将模式串向右“活动”尽可能远的距离后,继续进行比较。如下图所示:
next数组计算
假设
此时
pk=pj , 则有:next[j+1]=next[j]+1 ;pk≠pj , 此时,可把求next函数值的问题看成是一个模式匹配的问题。找到模式串中第next[k] 个字符和pj 对齐,……,依次类推,直到匹配成功, 则next[j+1]=next[k] ,或者不存在任何k‘(0<k‘<j) 满足:p0...pk‘=pj−k‘...pj ,则next[j+1]=0 ,表示从0号元素重新开始匹配。
C++版代码如下所示:
vector<int> getNext ( string&t )
{
size_t n = t.length();
vector<int>next(n,-1);
int i = 0, j = -1;
while ( i < n-1 )
{
if ( j == -1 || t[i] == t[j])
{
++i;
++j;
next[i] = j;
}
else
j = next[j];
}
for (int i = 0; i < next.size(); ++i)
cout << next[i];
cout << endl;
return next;
}
上述代码中与元素在数组中的下标索引一一对应。next[i]表示当第i号元素匹配失败时,当用t[next[i]]来匹配。因此next[0]=-1,表示无可用于匹配的元素,目标串应向右移动(即i++)。上述代码从next[1]开始计算,因为next[0]在初始化时已经设置为-1。
KMP算法代码
返回子串w在t中第一次出现的位置
int indexKMP( string& t, string&w, vector<int>& next )
{
int i = 0, j = 0;
int lengthT = t.length();
int lengthW = w.length();
while ( i < lengthT && j < lengthW )
{
if ( j == -1 || t[i] == w[j] ) //继续比较后继字符
{
++i;
++j;
}
else
j = next[j];
}
if ( j == lengthW )
return i - lengthW;
else
return -1;
}