C++的KMP实现

声明:这是我学过KMP后整理的笔记,目的只是为了将来复习的时候能快速记起KMP的用法和代码实现。因部分内容感觉不需要整理所以这篇博客并不详细完整,如果是要学习KMP建议找其他大神的博客系统学习。否则看懵了我不负责哟~

KMP的作用:优化匹配字符串。

大致思想:

如在“ABCDABCDEFABCDABCDAG”(我们称之为被匹配字符数组)中搜索“ABCDABCDAG”(匹配字符数组),前面有两个重复的“ABCD”,不匹配的时候就不需要一个一个往后推,直接把前缀“ABCD”推到后缀“ABCD” 匹配的那个地方,从那里往后推就行。

上面那段话有点绕。反正我是明白了。

要实现这一思想首先要先检测匹配字符数组中有没有重复的部分(前缀和后缀)。检测的方法是给每一个字符赋NEXT值。举例如下:(注意在这个例子中字符数组“ABCDABCDEFABCDABCDAG”被当作匹配字符数组,就是短的那个)

ABCDABCDEFABCDABCDAG的NEXT值分别为-1 0 0 0 0 1 2 3 4 0 0 1 2 3 4 5 6 7 8 5

‘A’的值为-1是因为如果是0的话一旦不匹配就会不断跳转到0,即A本身。这样就死在那了。

对了,NEXT值的含义是如果不匹配那么会跳转到第几位。所以G的NEXT 值为5。

好吧,如果看到上面还是不记得为什么NEXT值是5==(一般不会这样的。)

因为发现到了G不匹配,就会搜索有没有前缀是ABCDABCDA。发现没有。于是检测有没有前缀是ABCDA。 发现有,于是G跳转到第五个。‘B’。

综上可见NEXT值的计算很简单。所以代码实现如下:

int ne[100];///这个数组中盛放的是匹配字符串的next值
void GetNext(char *a)///这个函数是为了标记匹配字符串的next值
{
     int len = strlen(a);///先求字符串的长度,便于循环赋值
     int i = 0, j = -1;
     ne[0] = -1;
     while(i < len)
     {
          if(j == -1 || a[i] == a[j])
          {
               ne[++i] = ++j;
          }
          else j = ne[j];
     }
}
///实际上每求一个next值要循环两遍
然后就是根据NEXT值来简单快速匹配:

int KMP(char *a, char *b)
{
     int lena = strlen(a);
     int lenb = strlen(b);
     int i = 0, j = 0;
     while (i < lena && j < lenb)
     {
          if(j == -1 || a[i] == b[j])
          {
               j++;
               i++;
          }
          else
               j = ne[j];
     }
     if(j == lenb)
          return i-j+1;
     else
          return -1;
}
///这个代码的结果:如果能匹配则返回匹配代码在被匹配代码中首字符的位置;如果不能匹配则返回-1
只要明白原理这两个代码是非常容易搞明白的。

下面是一个完整的最简单KMP code:

#include "cstdio"
#include "iostream"
#include "cstring"
using namespace std;

int ne[20];///这个数组中盛放的是匹配字符串的next值
void GetNext(char *a)///这个函数是为了标记匹配字符串的next值
{
     int len = strlen(a);///先求字符串的长度,便于循环赋值
     int i = 0, j = -1;
     ne[0] = -1;
     while(i < len)
     {
          if(j == -1 || a[i] == a[j])
          {
               ne[++i] = ++j;
          }
          else j = ne[j];
     }
}
///实际上每求一个next值要循环两遍
int KMP(char *a, char *b)
{
     int lena = strlen(a);
     int lenb = strlen(b);
     int i = 0, j = 0;
     while (i < lena && j < lenb)
     {
          if(j == -1 || a[i] == b[j])
          {
               j++;
               i++;
          }
          else
               j = ne[j];
     }
     if(j == lenb)
          return i-j+1;
     else
          return -1;
}

int main()
{
     char s[100];///this is the main
     char f[100];///this is the one to be found
     scanf("%s", &s);
     scanf("%s", &f);
     GetNext(f);
     cout << KMP(s,f) << endl;

     return 0;
}
THE END.
  • 18
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值