KMP算法的简述
每一次比较时,当子串与主串不相等的时候,主串的指针不回溯,而是通过next函数所求得的值当作下一位子串开始比较的位置。(即尽可能地向右边滑动一段的距离,从而减少比较的次数)。
int Index_KMP(SString *S, int pos, SString *T) {
int next[MAXSIZE] ;
Get_Next( T, next);
int i = pos, j = 1;
while(i <= S->len && j <= T->len) {
if(S->data[i] == T->data[j] || j == 0) {
//j == 0是一个判断条件,当子串匹配到第一个字符的时候都没有匹配
//子串与主串的指针都要向后移动,重新从头开始进行匹配
++i;
++j;
} else {
j = next[j];
}
}
if(j > T->len)
return(i - T->len);
else
return 0;
}
next算法的描述
首先next函数是基于递推的思想的,KMP算法是基于next函数来实现的。
next的函数值,由上述的定义可以得到next[1] = 0,假设next[j] = k,说明最长的匹配的真前缀子串和后缀子串的长度为k-1,那么next[j+1]有以下两种情况:
(1)当T[j] = T[k]时,也就是说当T[j]失配的时候重新找到的匹配的位置与他相等,也就是说现在子串前k+1个字符相等,所以next[j+1]时,值为k+1,即next[j+1] = next[j] +1,一定要注意next值的定义。
(2)当T[j] != T[k]时,这时候求next值的问题我们可以看作是一个模式匹配的问题,匹配的过程中模式串既是主串又是模式串。其中1
①:若T[j] = T[k’],且k’ = next[k],那么next[j+1] = k’+1,即next[j+1] = next[next[k]]+1.
②:若T[j] != T[k],则继续比较T[j]和T[next[k’]],即比较T[j]和T[next[next[k]]].
然后一直这样下去直到k = 0都没有成功,则next[j+1] = 1.
void Get_Next(SString *T,int *next) {
int i = 1, j = 0;
next[1] = 0;
while(i < T->len) {
if(j == 0 || T->data[i] == T->data[j]) { //相等时,next的值等于j+1
++i;
++j;
next[i] = j;
} else {
j = next[j];//往前寻找更小的匹配的子串
}
}
}
nextval算法的描述
这是基于next的算法进行的,弥补next算法的缺陷的。
主要解决了模式串中大量连续重复的字符,nextval函数减少了主串的无用比较的次数
假设主串为:‘aaabaaaab’ 子串为:'aaaab’则对应的next函数值为下:
void Get_NextVal(SString *T, int *next, int *nextval)
{
int j = 2;//j = 1时,nextval[1]的值默认为 0所以从2开始
nextval[1] = 0;
Get_Next( T, next);
while(j <= T->len)
{
if(T->data[j] == T->data[next[j]])
{
nextval[j] = next[next[j]];
}
else{
nextval[j] = next[j];
}
j++;
}
}