在本期的字符串匹配算法中,我将给大家带来常见的两种经典的示例:
目录
(一)暴力匹配(BF)算法
1、思想
2、演示
3、代码展示
(二)KMP算法
1、思想
2、演示
1️⃣ BF和KMP的区别
2️⃣ K 的值求解
3️⃣ 求next数组的练习
3、代码展示
4、next数组的优化
(三)总结
大家看到上诉这段话时肯定是晦涩难懂的,需要例子支持
int BF(char *str,char *sub) //str:主串 sub:子串
{
assert(str != NULL && sub != NULL);
if(str == NULL || sub == NULL)
{
return -1;
}
int i = 0;
int j = 0;
int strLen = strlen(str);
int subLen = strlen(sub);
while(i < strLen && j < subLen)
{
if(str[i] == sub[j])
{
i++;
j++;
}
else
{
//回退
i = i-j+1;
j = 0;
}
}
if(j >= subLen)
{
return i-j;
}
return -1;
}
int main()
{
printf("%d\n",BF("ababcabcdabcde","abcd"));
printf("%d\n",BF("ababcabcdabcde","abcde"));
printf("%d\n",BF("ababcabcdabcde","abcdef"));
return 0;
}
j 的回退位置
针对上述这样的情况,我们就需要引出next数组
到这里大家对如何求next数组应该问题不大了,接下来的问题就是,已知next[i] = k;怎么求next[i+1] = ?
那么: Pk != Pi 呢?
void GetNext(int *next,const char *sub)
{
int lensub = strlen(sub);
next[0] = -1;
next[1] = 0;
int i = 2;//下一项
int k = 0;//前一项的K
while(i < lensub)//next数组还没有遍历完
{
if((k == -1) || sub[k] == sub[i-1])
{
next[i] = k+1;
i++;
k++;//k = k+1???//下一个K的值新的K值
}
else
{
k = next[k];
}
}
}
int KMP(const char *s,const char *sub,int pos)
{
int i = pos;
int j = 0;
int lens = strlen(s);
int lensub = strlen(sub);
int *next = (int *)malloc(lensub*sizeof(int));//和子串一样长
assert(next != NULL);
GetNext(next,sub);
while(i < lens && j < lensub)
{
if((j == -1) || (s[i] == sub[j]))
{
i++;
j++;
}
else
{
j = next[j];
}
}
free(next);
if(j >= lensub)
{
return i-j;
}
else
{
return -1;
}
}
int main()
{
char *str = "ababcabcdabcde";
char *sub = "abcd";
printf("%d\n",KMP(str,sub,0));
return 0;
}
练习模式串 t=‘abcaabbcabcaabdab’ ,该模式串的 next 数组的值为( D ) , nextval 数组的值为 ( F )A . 0 1 1 1 2 2 1 1 1 2 3 4 5 6 7 1 2B . 0 1 1 1 2 1 2 1 1 2 3 4 5 6 1 1 2C . 0 1 1 1 0 0 1 3 1 0 1 1 0 0 7 0 1D . 0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2E . 0 1 1 0 0 1 1 1 0 1 1 0 0 1 7 0 1F . 0 1 1 0 2 1 3 1 0 1 1 0 2 1 7 0 1
BF(Brute Force)和KMP(Knuth-Morris-Pratt)算法是两种字符串匹配算法,它们的主要区别在于匹配过程中的策略和效率。
BF算法:
KMP算法:
以下是关于上述两种算法的小结: