BF算法
当我们在进行字符串匹配时,我们会把主串和模式串,从某个位置,我们记为【pos】,开始匹配,每匹配成功一个字符,就让i加一。可一旦“失配”,我们就会让i回溯,从pos的下一个字符开始,重新执行上面的过程,直到模式串被匹配完。
int Index_BF(string str1, string str2, int pos = 1)
{
int i = pos, j = 1;
while(i < str1.length() && j < str2.length())
{
if(str1[i] == str2[j]) {i++;j++;}
else {pos++;i=pos;j=1;}
}
if(j == str2.length())
return i - j + 1;
else
return 0;
}
KMP算法
KMP算法的精髓所在,就是当“失配”时,不需要将i重新回溯到pos的下一个。 而是将模式串向右滑行,尽可能远的距离。因为在模式串中,当“失配”时,如果当前“失配”字符的前k个字符,和模式串的最开始的k个字符,如果相等,那么这k个字符,是不需要再进行比较的,直接让主串的第i个字符,和模式串的第k+1个字符开始比较就可以了。
比如当我们比较
i从8到15,在15时“失配”。本来按照BF算法,i是要从9重新开始的。但我们仔细观察,可以发现在模式串中,相对于这个失配字符,前三个字符与后三个字符是相等的
所以我们可以让i不动,仍然为15,但让模式串的j等于“相等字符数加一”也就是4,让主串的第十五个字符,和模式串的第四个字符进行匹配。这样前面的三个字符就不需要再匹配了。
那么相对于模式串中的f,它的k值,就为3+1;全部字符的k值,我们存在一个叫做next的数组中,它记录了当这个字符失配时,我么跳到哪一个字符。技巧:它的值为当前字符的,前面的,字符串的,首尾重合数加一。 不过这个技巧只能用来应付考试,计算某个模式串的next数组。这个求next数组的方法,代码实现好像有点困难。
next数组的计算方法
//比较第i个字符,与第j个字符是否相等
//如果相等,那么就让下一个字符的next值等于j+1
//如果不相等,就好比失配,就让j往前等于next[j]
//重复第一步,直到j等于零
//j等于零,说明第一个字符都与第i个字符不相等
代码实现
#include<iostream>
using namespace std;
void Get_Next(string str,int next[])
{
//比较第i个字符,与第j个字符是否相等
//如果相等,那么就让下一个字符的next值等于j+1
//如果不相等,就好比失配,就让j往前等于next[j]
//重复第一步,直到j等于零
//j等于零,说明第一个字符都与第i个字符不相等
int i = 1, j = 0;next[1] = 0;
while(i < str.length())
{
if(j == 0 || str[i] == str[j]) {j++;i++;next[i] = j;}
else j = next[j];
}
}
int Index_Kmp(string str1, string str2, int pos = 1)
{
int next[100];
Get_Next(str2,next);
int j = 1;
while(pos < str1.length() && j < str2.length())
{
if(j == 0 || str1[pos] == str2[j]) {pos++;j++;}
else j = next[j];
}
cout<<j<<" "<<pos;
if(j == str2.length())
return pos - j + 1;
else
return false;
}
int main()
{
string str1, str2;
cin>>str1>>str2;
cout<<Index_Kmp(str1,str2);
//#号不能删
/*测试数据
#acabaabaabcacaabc
#abaabcac
*/
}
我也只是做个大概的总结,具体的,还是需要看书的。
来源:CSDN
作者:沐目_Chen
链接:https://blog.csdn.net/weixin_44077544/article/details/104107943