1.KMP算法:
KMP算法是一种改进的字符串匹配算法
KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
具体实现就是通过一个next数组实现,数组本身包含了模式串的局部匹配信息。
KMP算法的时间复杂度O(m+n)
2.BF算法:
BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,
BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,
若相等,则继续比较S的第二个字符和 T的第二个字符;
若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。
BF算法是一种暴力算法。
KMP和BF唯一不一样的地方在于:
此时主串跟子串匹配失败,
如果是BF算法的话,i会回退到下标1的位置,j会回退到下标0的位置再次进行匹配
如果是KMP算法的话,i不会回退,只有j会回退,我们会感到惊讶,怎么做到的啊?
那么我们如何在主串中找到和子串匹配的一部分串呢?
这里就需要用到next数组了
next数组的作用:
保存子串某个位置匹配失败后回退的位置
定义:
next[j]=k;
如果j下标匹配失败时,那么下次匹配时j回退到下标为k的位置
手求next数组:
而k的值是这样求的:
1:找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标0开始,另一个以下标j-1结尾.
2:不管怎样都有:next[0]=-1;next[1]=0;
next数组也可以从0开始,也就是next[0]=0;
只需把我们上面那种形式所求出的next数组中的值全部加1即可
下面是两个例子,大家可以先做一下,巩固巩固,我们还要从这两个例子中再说明一些重要的点
友情提醒:
通过这两个题,我们可以发现:
1.next数组不可能跳着加!!!,所以,如果你求出来的next数组有跳着加的现象,那证明你做错了
2.也就是说next数组满足若next[j]=k,p[j]==p[k],那么next[j+1]=k+1;(p是子串)
/*
str:代表主串
sub:代表字串
pos:代表从主串的pos位置开始找
*/
void GetNext(char* sub, int* next,int lenSub)
{
next[0] = -1;
//子串长度为1,直接返回即可
if (lenSub == 1)
{
return;
}
next[1] = 0;
int i = 2;//当前i下标
//因为此时还不知道next[i]的值,只知道next[i-1]的值和sub[k]的值
int k = 0;//前一项的k
while(i<lenSub)
{
//k==-1,此时不能再进行回退了,否则子串会发生越界
//匹配成功或者k回退到k=-1时,利用next[i-1]=k,推出=>>next[i]=k+1;
//i和k往后走,继续求解next数组
if (k==-1 || sub[i - 1] == sub[k])
{
next[i] = k + 1;
i++;
k++;
}
//sub[i-1]!=sub[k],即匹配不成功,k回退
else
{
k = next[k];//k回退
}
}
}
int KMP(const char* str,const char* sub, int pos)
{
//对参数的正确性的判断
assert(str!=NULL && sub!=NULL);
int lenStr = strlen(str);
int lenSub = strlen(sub);
if (lenStr == 0 || lenSub == 0)
{
return -1;
}
if (pos < 0 || pos >= lenStr)
{
return -1;
}
int* next = (int*)malloc(sizeof(int) * lenSub);
assert(next != NULL);
GetNext(sub, next, lenSub);
//开始遍历两个串
int i = pos;//遍历主串
int j = 0;//遍历子串
while (i < lenStr && j < lenSub)
{
//对应位置相等,往后走
//j==-1,此时不能再进行回退了,否则子串会发生越界
if (j == -1 || str[i] == sub[j])
{
i++;
j++;
}
//否则:i不动,j回退
else
{
j = next[j];
}
}
//子串遍历结束,意味着匹配成功
free(next);
next = NULL;
if (j >= lenSub)
{
return i - j;
}
//主串遍历成功,子串却没有遍历成功,意味着匹配失败
return -1;
}
//验证
int main()
{
printf("%d\n", KMP("ababcabcdabcde", "abcd", 0));//5
printf("%d\n", KMP("ababcabcdabcde", "abcdf", 0));//-1
printf("%d\n", KMP("ababcabcdabcde", "e", 0));//13
printf("%d\n", KMP("d", "e", 0));//-1
}
//验证成功
以上就是KMP算法的详解,希望能对大家有所帮助!