当j=1时,next[j]=0;
其他情况,next[j]=1
next[j]=max{1<k<j,且p1...k-1 = pj-k+1....pj-1},此集合不为空时。
//通过计算返回子串T的next数组
void get_next(string T,int *next)
{
int i,j;
i = 1;
j = 0;
next[1] = 0;
while(i < T[0]) //此处T[0]表示串T的长度
{
if(j == 0 || T[i] == T[j]) // T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
{
++i;
++j;
next[i]=j;
}
else
{
j = next[j]; //若字符不相同,则j值回溯。
}
}
}
//返回子串T在主串S中pos个字符之后的位置。若不存在,则函数返回值为0
//T非空,1<=pos<=StrLength(S)
int Index_KMP(string s,string T,int pos)
{
int i = pos; //i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配
int j = 1; //j用于子串T中当前位置下标值。
int next[255]; //定义一next数组
get_next(T,next); //对串T做分析,得到next数组。
while(i <= S[0] && j <= T[0]) //若i小于S的长度且j小于T的长度时,循环继续
{
if(j == 0 || S[i] == T[j]) //两字母相等则继续,与朴素算法增加了j = 0判断
{
++i;
++j;
}
else //指针后退重新开始匹配
{
j = next[j]; //j退回合适的位置,i值不变。
}
if(j > T[0])
return i - T[0];
else
return 0;
}
}
T的长度时m,时间复杂度为O(m),while循环的时间复杂度为O(n),整个算法的时间复杂度为O(n+m).
朴素模式时间复杂度为O((n-m+1)*m)
KMP算法仅当模式与主串部分匹配时,才能展现其优势。
//求模式串T的next函数修正值并存入数组nextval
void get_nextval(string T,int *nextval)
{
int i,j;
i = 1;
j = 0;
nextval[1] = 0;
while(i < T[0])
{
if(j == 0 || T[i] == T[j])
{
++i;
++j;
if(T[i] != T[j]) //若当前字符与前缀字符不同
nextval[i] = j; //则当前j为nextval在i位置的值。
else
{
nextval[i] = nextval[j]; //如果与前缀字符相同,则将前缀字符的nextval值赋给nextval在i位置的值
}
}
else
{
j = nextval[j]; //若字符不相同,则j值回溯。
}
}
}
next值是前缀与后缀比较,相等则是下一位的值,不相等则是当前值。
nextval是a为字符与其next指向的b位字符比较,相等则a的nextval值赋给b的nextval值;不等则,a的next值赋给a的nextval值。