KMP算法
克努斯-莫里斯-普拉特字符串查找算法(英语:Knuth– Morris–Pratt algorithm,简称为KMP算法)
例:
在文本串"ABCDABCEABCEABCFABCF"中查找 子串“ABCEABCF"的下标
文本串T:ABCDABCEABCEABCFABCF
字串 P:ABCEABCF
暴力查找:
- 先找到P的第一个字符在T中的位置 iPos,
- 从iPos开始 依次比较后面的字符
- 如果全部匹配就返回iPos,否则 重复第一步。
设T的长度是n,P的长度是m,
则时间复杂度为O(m*n)。
KMP
第一种情况:
比较前:
文本串T:ABCDABCEABCEABCFABCF
模式串P:ABCEABCF
前3次比较成功,第4次比较D和E不相等。由于BC匹配成功且与A不相等,所以P向后移动3个字符。
比较后
文本串T:ABCDABCEABCEABCFABCF
模式串P: ABCEABCF
第二种情况:
比较前:
文本串T:ABCDABCEABCEABCFABCF
模式串P: ABCEABCF
前7次比较成功,第8次比较E和F不等,F前3个字符ABC均与T匹配成功,且与P的前3个字符ABC相同,所以P向右移动4个字符。
比较后:
文本串T:ABCDABCEABCEABCFABCF
模式串P: ABCEABCF
#pragma once
#include<string>
#include<vector>
using namespace std;
class CKmp
{
public:
CKmp(string str);
int match(string szPattern);
private:
void BuildNext(string szPattern, vector<int> &vecNext);
private:
string m_szText;
};
#include "Kmp.h"
CKmp::CKmp(string str):m_szText(str)
{}
int CKmp::match(string szPattern)
{
if (szPattern.empty())
{
return -1;
}
vector<int> vecNext;
BuildNext(szPattern, vecNext);
for (int iText = 0, iPattern = 0; iText < m_szText.size(); )
{
if (iPattern >= (int)szPattern.length())
{
return iText - (int)szPattern.length();
}
if (iPattern < 0 || szPattern[iPattern] == m_szText[iText])
{
iPattern++;
iText++;
}
else
{
iPattern = vecNext[iPattern];
}
}
return -1;
}
void CKmp::BuildNext(string szPattern, vector<int> &vecNext)
{
size_t nSize = szPattern.size();
vecNext.resize(nSize,-1);
int t = -1;
for (size_t i = 1; i < nSize; )
{
if (t < 0 || szPattern[i - 1] == szPattern[t])
{
vecNext[i] = ++t;
i++;
}
else
{
t = vecNext[t];
}
}
}
KMP算法中,文本串的指针不后退,只后退子串的指针。时间复杂度为O(m + n)