1.手动推算KMP算法
KMP算法是BF算法升级版本
BF算法就是暴力搜索,一个一个的去匹配
主串指针所指向的字符:a
模式串指针指向的字符:c
此时不匹配:模式串指针指向开始位置,主串指针指向第二个位置****
当遇到如下这种情况时候:
太浪费时间了,每次模式串到达最后一个位置才知道匹配失败,并且每次都匹配到模式串的最后一个字符才知道,确实花费时间
所以从而引入KMP算法-----串的模式匹配
KMP算法-----求解next数组
KMP算法-----主串匹配模式串
求解next数组步骤
例:
刚开始初始化next数组,next[1] = 0,k = 0, j = 1
next数组值的计算:
k:记录前后缀匹配长度,并且不匹配时候,k = 1,表示没有一个匹配的,下限是0,到达0说明一个匹配的没有
j:遍历串的每一个字符位置
前后缀理解:
例如字符串 abcde
前缀:abcd
后缀:bcde
循环:
if 匹配成功 或者 回溯达到界限k = 0*:
当前next的值:k+1
else 匹配失败:
当前k的值:通过next数组回溯得到新的k
第一次:填写next[2]元素值,k = 0,j = 1, 由于k = 0,所以next[++j] = ++k, 也就是next[2] = 1
第二次:填写next[3]的值,k = 1, j = 2, 他的前面元素 a b,k = 1也就是数组元素a,j = 2也就是数组元素 b,a不等于b,不匹配,然后根据next数组回溯,得到新的k值,k = next[k] = next[1]得到0,由于k = 0,所以next[++j] = ++k,也就是next[3] = 1
第三次:填写next[4]的值,j= 3,k = 1,他前面的元素为 a b a, j = 3也就是数组元素a,k=1也就是数组元素a,a等于a,匹配成功,所以next[++j] = ++k,所以next[4] = 2
第四次: 填写next[5]的值,j = 4, k = 2,他的前面元素, a b a a,j = 4也就是数组元素a,k=2也就是数组元素b,a不等于b,通过next数组回溯,得到新的k值,k = next[2] = 1,此时继续比较,k = 1数组元素为a,j=4数组元素为a,此时a等于a,成立,next[++j] = ++k,next[5] = 2
第五次: 填写next[6]的值,j = 5, k = 2,他前面元素为a b a a b, j = 5数组元素是b,k=2数组元素是b,b等于b匹配,next[++j]=++k, next[6] = 3
最终next数组算完。
最终next数组算出来了,next[] = {0,1,1,2,2,3}, 下标从1开始
主串与模式串匹配
if匹配成功或者j = 0
i++,j++
else
通过next数组回溯得到新的j值
匹配成功:主串与模式串指针分别往后走
匹配失败:通过next数组回溯,重新定位模式串的位置,得到模式串新的位置与主串当前位置比较
注意:当一直失败,一直回溯,下限是0,就要主串位置+1,模式串+1
当一开始匹配失败,就要回溯,j = 0, 当j = 0,然后,i++,j++,此时走到主串当前位置后面一个位置去,模式串到达第一个位置,j = 1
示例:
第一趟时候,i = 2, j = 2,不匹配,通过next数组回溯,j = next[j] = next[2] = 1
第二趟时候,i = 2, j = 1,不匹配,通过next数组回溯,j = next[j] = next[1] = 0,当j等于0时候,i++,j++,得到主串到达下一个位置,模式串到达第一个位置,i = 3, j = 1
当i = 8,j = 6时候,此时不匹配,通过next数组回溯, j = next[j] = next[6] = 3, i不动,i还是8,j变成3
第四趟时候,正好可以吧模式串在主串中找到,结束,匹配完成,只需要4次就匹配成功
最终模式串在主串的12-6 = 6位置上
2.BF算法代码实现
//BF算法-----主串str1, 模式串str2
int BF(char str1[], char str2[])
{
int i = 0, j = 0;
while (str1[i] && str2[j])
{
if (str1[i] == str2[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
count1++;
}
if (!str2[j])
return (i - j + 1);
}
3.KMP算法代码实现
//KMP算法
int KMP(char str1[], char str2[])
{
int next[100];
int i = 0, j = 0;
get_next(str2, next); //获得next数组
while (str1[i] && str2[j])
{
if (j == 0 || str1[i] == str2[j])
{
i++;
j++;
}
else
{
j = next[j];
}
count2++;
}
return i - j + 1;
}
3.1求解next数组
//求next数组 模式串str, next数组---模式串回溯的位置
void get_next(char str[], int next[])
{
//1.初始化next数组,初始化k和j
next[0] = -1;
int k = -1;
int j = 0;
//循环
while (str[j])
{
if (k == -1 || str[k] == str[j])
{
k++;
j++;
next[j] = k;
}
else
k = next[k];
}
}
最终两个算法测试比较
输入主串:aaaaaaaaaaaaaaac
输入模式串:aaaac
BF:60次
KMP:27次
输入主串:acabaabaabcacbc
输入模式串:abaabc
BF:18次
KMP:14次