两个字符串匹配,匹配成功时,i和j同时后移一位。直至子串匹配完(即j>lensub)
而BF算法和KMP不同之处在于:
- BF算法,当匹配失败时,j直接回到0位置,i回到上次的位置加一(即i-j+1)。这样前面匹配过的又要重新来一遍,浪费了好多时间
- KMP算法,在匹配失败的时候,i不动,j回到他next数组对应的下标位。
//BF
int BF(char *s,char *sub,int pos)
{
int i = pos;//主串
int j = 0;//子串
int lens = strlen(s);
int lensub = strlen(sub);
while(i < lens && j < lensub)
{
if(s[i] == sub[j])
{
i++;
j++;
}
else
{
i = i-j+1;
j = 0;
}
}
if( j >= lensub)
{
return i-j;
}
else
{
return -1;
}
}
KMP算法,首先要创建一个next数组来保存对应的next值。
- next数组保存的值,即匹配成功的子串长度(除了第一位是-1)
- 需要比较的则是该字符串i-1位置和k位置的值是否相等。比如现在所在位置,i与k还是匹配失败,则k回到-1位置,因为不存在-1位置,说明主串i之前的匹配完了,还是失败。此时,需要i往前走一步,继续匹配。
//next数组的建立
void GetNext(int *next, char *sub)
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int k = 0;//前一项(也表示匹配到的真子串的长度)
int i = 2;//后一项
while (i < lensub)
{
if (k == -1 || sub[k] == sub[i - 1])//k==-1即主串与子串的第一位都不相等 或匹配成功
{
next[i] = k + 1;//next数组其实存放的是匹配成功的子串长度 如果匹配成功了,长度加一,即next++
i++;
k++;
}
else
{
k = next[k];//k回到next[k]的位置,再进行比较。如果一直不相等,最后k==-1,进入上面的语句
}
}
}
手动推导next数组和nextval数组
- next数组各位的值,是从主串第一位开始,各位的前一位结束所寻找到的真子串的长度。(除了第一位是-1。第二位是0 固定的)
- nextval数组是根据next数组计算的。比如i和j位置。先寻找next数对应下标的值,i位置的两个都是a,相等,所以nextval的值就等于next数组0下标处的值。
- J位置的两个不相等,所以nextval值等于此位置next的值
next数组建立好了,根据next数组进行kmp的匹配
int KMP(char *s, char *sub, int pos)
{
int i = pos; int j = 0;
int lens = strlen(s);
int lensub = strlen(sub);
int *next = (int *)malloc(sizeof(int)*lensub);
assert(next, sub);
GetNext(next, sub);
while (i < lens&&j < lensub)//当两个字符串都没遍历完
{
if (j==-1||s[i] == sub[j])//匹配成功,往后走继续匹配
{
i++;
j++;
}
else
{
j = next[j];//匹配失败,回到该位置next数组代表的下标位置
}
}
free(next);
next = NULL;
if (j >= lensub)
{
return i - j;
}
else
{
return -1;
}
}