KMP算法
在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示T[1...j-1]中最长后缀的长度等于相同字符序列的前缀。
数据结构的算法书上的定义,这里假设模式串中的T[0],以及主串中的S[0]都是用来存储字符长度的。
对于next[]数组的定义如下:
1)next[j]=0 j=1
2)next[j]=max k: 1<k<j T[1...k-1]=T[j-k+1,j-1]
3)next[j]=1 其他情况
即next[j]=k>1时,表示T[1...k-1]=T[j-k+1,j-1]
因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=0,则将i右移1位,并将j置1,继续进行比较。
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASLBLE -1
#define OVERFLOW -2
#define MAXSTRLEN 255 //用户可在255以内定义最大串长
typedef char SString[MAXSTRLEN+1]; //0号单元存放串的长度
void get_next(SString T,int next[]){
// 算法4.7
// 求模式串T的next函数值并存入数组next
/*
KMP算法的关键在于求算next[]数组的值,即求算模式串每个位置处的最长后缀与前缀相同的长度, 而求算next[]数组的值有两种思路,第一种思路是用递推的思想去求算,还有一种就是直接去求解。
1.按照递推的思想:
根据定义next[1]=0,假设next[j]=k, 即T[1...k-1]==T[j-k+1,j-1]
1)若T[j]==T[k],则有T[1..k]==T[j-k+1,j],很显然,next[j+1]=next[j]+1=k+1;
2)若T[j]!=T[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,k=next[k]。
*/
int k=0,j=1;
next[1]=0;//根据数据结构书上的定义第一个应为0
while(T[j]!='\0')
{
if(k==0||T[j]==T[k])
{
k++;
j++;
next[j]=k;
}
else
{
k=next[k];
}
}
return ;
}
int Index_KMP(SString S,SString T,int pos){
// 算法4.6
// 利用模式串T的next函数求T在主串S中第pos个字符之后的位置
int j=1,i=1;
int next[1000+10];
get_next(T,next);//计算next值
while(i<=S[0]&&j<=T[0])
{
if(j==0||S[i]==T[j])
{
i++;
j++;
}
else
{
j=next[j];
}
if(j>T[0])//T串已经比较完毕,确定是主串的子串
{
return i-T[0];
}
}
return 0;//否则返回值为0
}
int main()
{
SString T,S;
int i,j,n;
char ch;
int pos;
scanf("%d",&n); // 指定n对需进行模式匹配的字符串
ch=getchar();
for(j=1;j<=n;j++)
{
ch=getchar();
for( i=1;i<=MAXSTRLEN&&(ch!='\n');i++) // 录入主串
{
S[i]=ch;
ch=getchar();
}
S[0]=i-1; // S[0]用于存储主串中字符个数
ch=getchar();
for( i=1;i<=MAXSTRLEN&&(ch!='\n');i++) // 录入模式串
{
T[i]=ch;
ch=getchar();
}
T[0]=i-1; // T[0]用于存储模式串中字符个数
pos= Index_KMP(S,T,0); //答案pos
printf("%d\n",pos);
}
return 0;
}
本文某些解释参考http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html海子大神的,不过有些定义是修改了一下