Code:
//KMP
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
int next[maxn];
void GetNext(char *P) ; //未改进的KMP,next[i]数组中代表的值是如果当前i位置匹配不成功, 指针指到模式串的哪一个位置(下标)
void GetNNext(char *P); //改进的KMP
void Find(char *T, char *P)
{
int len1 = strlen(T), len2 = strlen(P);
GetNext(P);
// for(int i = 0; i < len2 ; i++)
// cout << next[i] << " ";
// cout << endl;
GetNNext(P);
int j = 0;
for(int i = 0; i < len1; i++)
{
while(j && P[j] != T[i]) j = next[j];
if(P[j] == T[i]) j++;
if(j == len2)
{
printf("找到了: ");
printf("%d\n", i-len2+1);
return ;
}
}
printf("没找到\n");
return ;
}
/*
字符串匹配的原理:P[0]匹配不成功,只能让指向被查找串的指针后移,找到一个能和模式串第一个对应的字符
和其中某一个匹配不成功,说明前面已经有一部分匹配成功了,让指针按照所预先处理的next值进行移动
某一个字符串匹配成功, 指向模式串和查找串的指针都向后移动
指向寻找串的指针越界,说明没找到,指向模式串的指针越界,说明找到了 当前查找串的指针 - 模式串长度 + 1
就是匹配成功的第一个位置的下标
KMP算法的核心: next数组的求解(递推法求解)
先赋初值:和第一个匹配不成功, 那只能向后找喽 next[0] = 0;
和第二个匹配不成功, 也只能从头开始找,因为和第二个不匹配,也就是再去和第一个配,也就是从头开始找了
和后面的不匹配 !!!! KMP的精华:
开始向回找,找看有没有能够相等的前缀 while(j && P[i] != P[j]) j = next[j]; 这样一直向后退
知道有一个不满足的,然后可以用它来计算它的下一个,
如果P[i] == P[j] next[i+1] = j+1;
如果P[i] != P[j] next[i+1] = 0; 前功尽弃
为什么是下一个呢: 因为我们所寻找的一直都是它前面的那一部分
*/
void GetNext(char *P)
{
int len = strlen(P);
next[0] = 0, next[1] = 0;
for(int i = 1; i < len; i++)
{
int j = next[i];
while(j && P[i] != P[j])
j = next[j];
next[i+1] = P[i] == P[j] ? j+1 : 0; //如果不对直接返回开头
}
}
void GetNNext(char *P)
{
int len = strlen(P);
for(int i = 1; i < len; i++)
{
if(P[i] == P[next[i]])
next[i] = next[next[i]];
}
}
int main()
{
char Text[10000], Purpose[100000];
memset(next, 0, sizeof(next));
scanf("%s", Text);
scanf("%s", Purpose);
Find(Text, Purpose);
return 0;
}