好久没写博客了,最近在学数据结构,今天来分享一下字符串的匹配算法。
朴素的模式匹配算法
这个方法比较容易理解(简称:暴力匹配),大概思路是这样的:从S的第一个字符S0开始,将P中的字符依次和S中字符比较,若S0=P0 && …… && Sm-1 = Pm-1,则证明匹配成功,剩下的匹配无需进行了,返回下标0。若在某一步Si != Pi 则P中剩下的字符也不用比较了,不可能匹配成功了,然后从S中第二个字符开始与P中第一个字符进行比较,同理,也是知道Sm = Pm-1或者找到某个i使得Si != S-1为止。依次类推若知道以S中第n-m个开始字符为止,还没有匹配成功则证明S中不存模式P。
void pattern_match(seqstring* p, seqstring* t)//寻找模式p在t中的位置
{
int i, j, succ;
i = 0; succ = 0;
while ((i <= t->length - p->length) && !succ)
{
j = 0; succ = 1;
while ((j < p->length) && succ)
{
if (p->str[j] == t->str[i + j])j++;
else succ = 0;
}
++i;
}
if (succ)printf("nice! 与原字符串 %d-%d 字符串成功匹配。\n",i,i+t->length-1);
else printf("匹配失败\n");
}
快速模式匹配算法(KMP)
上面的算法易理解,但代码效率不高。KMP算法关键在于如何求得next值。作一个对比,朴素的模式匹配算法是:从主串第i个位置开始与模型字符窜p匹配,若匹配失败,则返回来再从第i+1个位置开始检索匹配,直至结束。也就是说(i+1)-i=1 ,主串每次移动的只是一个元素,但这样效率低下,所以有的元素处 他就可以一下子移动好几个位置,从而我们的好几个位置就等于next[i]。
废话少说,直接上代码
int i, j = 0, next[20]; next[0] = 0;
for (i = 1; i < p->length; ++i)
{
while (j > 0 && p->str[i] != t->str[j])j = next[j - 1];
if (p->str[i] == p->str[j])j++;
next[i] = j;
}
求next主要分为四步:
1、初始化
int i, j = 0, next[20]; next[0] = 0;
2、前后缀不相同
while (j > 0 && p->str[i] != t->str[j])j = next[j - 1];
3、前后缀相同
if (p->str[i] == p->str[j])j++;
4、求next
next[i] = j;
接着就比较简单了,利用next值进行匹配求值。
i = 0; j = 0;
while (i < t->length && j < p->length)
{
if (j==0||t->str[i] == p->str[j])
{
i++; j++;
}
else j = next[j - 1];
}
KMP源码如下:
void KMP_match(seqstring* t, seqstring* p)
{
int i, j = 0, next[20]; next[0] = 0;
for (i = 1; i < p->length; ++i)
{
while (j > 0 && p->str[i] != t->str[j])j = next[j - 1];
if (p->str[i] == p->str[j])j++;
next[i] = j;
}//求next
i = 0; j = 0;
while (i < t->length && j < p->length)
{
if (j==0||t->str[i] == p->str[j])
{
i++; j++;
}
else j = next[j - 1];
}
if (j == p->length)printf("匹配成功:%d-%d \n", i - p->length + 1, i);
else printf("匹配失败!\n");
}
最后如果大家还有不懂的话,附赠视频希望可以帮到你哦!
https://www.bilibili.com/video/BV1M5411j7Xx
https://www.bilibili.com/video/BV1tW41157tv/?spm_id_from=333.788.videocard.3