步骤:
(1) 首先根据模式串p的各 模式子串 计算 最长公共子串 (公共部分肯定适配)
(2) 根据公共子串求出前缀表,前缀表表示模式串的 上一个模式子串最大公共前后缀数;
根据前缀表,发现失配时要移动的位置(或移动长度)都跟上一个模式子串相关,就干脆把前缀表向后移动一位,0位置值为-1,得出next数组,next数组 表示 失配时 模式串需要匹配的位置。
KMP代码:
#include <iostream>
#include <cstring>
using namespace std;
static int index_next[1024] = { 0 };
void GetNext(char* p, int next[])
{
int pLen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < pLen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k]; //失配,k移动到下一个位置,即上个最大公共模式子串的前后缀数
}
}
}
int KmpSearch(const char* s, const char* p)
{
int i = 0;
int j = 0;
int sLen = strlen(s);
int pLen = strlen(p);
while (i < sLen && j < pLen)
{
//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if (j == -1 || s[i] == p[j])
{
i++;
j++;
}
else
{
//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = index_next[j];
}
}
if (j == pLen)
return i - j;
else
return -1;
}
int main() {
const char *s = "d3ababc";
const char *p = "abab";
GetNext((char *)p, index_next);
int pos = KmpSearch(s, p);
cout << pos;
}