【KMP】算法,未改进C++

首先是部分入门解释:

1:求next数组

当我们假设 模式串patten 为 aaabc时,
     a a a b c
对应的 NEXT数组为:
    -1 0 1 2 0。
Next 数组的含义:
  求next数组的时候,对于模式串的 J 位置 ,考察patten[ 0 ].到patten[j-1]组成的字符串 最长且相等的前缀和后缀。
假设最大相等前缀和后缀长度为k,则有k使得  p[0]p[1]p[2]......p[k-2]p[k-1] = p[j-k]p[j-k+1]......p[j-2]p[j-1]。
  先理解 前缀 和 后缀,例 "aaabc" 字符串的前缀,后缀各有4种,相互独立的。
前缀           后缀
a           a a b  c
a a            a b c
a a a            b c
a a a b            c
前缀不包含 最后一个字符,
后缀不包含 第一个字符。
patten[0]前无字符,亦无后缀,所以next[0]=-1;表示不存在。
patten[1],在patten[0]~patten[0]找前后缀,均为空,next[1]=0;
patten[2],最长相等前缀 'a',后缀为  'a',next[2]=1;
patten[3],最长相等前后缀为 ‘aa’和‘aa’ ( 即前缀 patten[0]patten[1],后缀 patten[1]patten[2])next[3]=2;
patten[4],后缀中含有 patten[3]=b,前缀没有 ‘b’,next[4]=0;
 求该数组过程如下:
算法解释如下:(关于回溯过程的解释,说有些啰嗦,可以自己求一下,我的过程在最下面的贴图上)

2 :KMP解释

在BF暴力算法中,假如从文本串的第 i 个字符来开始于模式串匹配。当匹配到模式串的第j位发现失配

即text[i+j] != patten[j]的时候,我们又从文本串的第i+1个位置来重新开始匹配。

可以看到每次失配之后,我们需要从文本串的下一个位置[ i+1 ]匹配,模式串从第一个字符重新开始于文本串匹配。并且在已经知道很多字符都配不上的情况下,还要这样一个一个字符移动着去匹配,是非常浪费时间的。

假设文本串长为 n,模式串长为 m,BF暴力穷举方法时间复杂度O(n*m),

而KMP算法的实质就是,当遇到text[i+j] != patten[j]的时候,但是我们知道模式串中的 0~j-1 位置上的字符已经于i ~ i+j-1位置上的字符是完全匹配的。这样我们可以在 0 ~ (j-1) 中找到一个前缀A和后缀B相等并且最长的那个串,然后将A移动到B的位置再开始重新匹配即可。

这样就减少了一些不必要的匹配。时间复杂度O(n+m)

借用其他博主的图片和字符串

patten模式串和next数组
模式串patten和next数组

准备好next数组后开始kmp匹配,开始匹配位置  i=0,可以看到,前面的红色黄色处均匹配,在蓝色标(J=5)记处不匹配,蓝色处字符对应的next数组值为 2 ,说明 蓝色字符C前面最长相等的前后缀为 a b,长度为2,因为红色格子表示前后缀相等,所以把模式串划过去,直接让 黄色格子 a 直接对准 上次蓝色格子 C对应的文本串位置

kmp匹配1

模式串滑过去后如图,这样就避免了BF算法中的 i=0匹配失败,继续匹配不可能匹配的 i=1,i=2两个位置,恰好移动后,模式串和文本串匹配,假设模式串和文本串不匹配,模式串就继续滑动。

kmp_2

 

代码如下

/* KMP算法
   未改进的
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn=1000;    //假设最长字符串长度
char text[maxn];        //文本串(目标串 被检测)
char patten[maxn];      //模式串
int next[maxn];         //模式串的 next数组
/*
*/
void GetNext(){         //获取 next数组
    int Len_p=strlen(patten);
    next[0]=-1;
    int k=-1,j=0;
    while(j<Len_p){
        if(k == -1 || patten[j] == patten[k]){
            ++k; ++j;
            next[j]=k;
        }else{
            k=next[k];
        }
    }
}

int KMP(){                //KMP算法
    int Addr=-1,i=0,j=0;
    int Len_p=strlen(patten),Len_t=strlen(text);
    while(i<Len_t){
        if(j == -1 || text[i] == patten[j]){
            ++i; ++j;
        }else{
            j=next[j];
        }
        if(j == Len_p){
            return i-Len_p;
            break;
        }
    }
    return Addr;
}
int main(){
    scanf("%s%s",patten,text);
    GetNext();
    for(int i=0;i<strlen(patten);i++){
        printf("%d ",next[i]);
    }   printf("\n");
    printf("%d",KMP());
    return 0;
}

运行如下:

第一行输入 模式串 asd,第二行输入文本串 asdf,第一行结果是模式串的next数组,第二行为模式串第一次出现在文本串的位置

 结果

求模式串“aaabc”的next数组的算法每一步

next

引用参考https://blog.csdn.net/suguoliang/article/details/77460455#commentBox

博主:黑脉金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值