KMP(模板)

老子叫甜甜 提交于 2019-12-01 13:32:32

 

kmp算法是解决单模匹配问题的算法,难点在于求next[]数组

求next[]数组:对于模板串的所有前缀子串的最长公共前后缀的长度,就是next[]数组的值

eg:主串为cbbbaababac  子串为ababac

初始化next[0]=-1;

         子串的最长公共前后缀长度

a                           -->0                             next[1]=0

ab                        -->0                             next[2]=0

aba                      -->1                             next[3]=1

abab                   -->2                             next[4]=2

ababa                -->3                              next[5]=3

next[]数组的作用是在当子串在和模板串失配的时候,next[]数组提供下一个字串的字母,和当前位置的模板串字母匹配

eg:模板串是cbbbaababac,子串是ababa

子串下标:                        0    1   2   3   4   

                                           a  b  a  b  a 

失配跳转位置next[]:-1   0   0    1   2   

 

这里解释一下:当子串和模板串失配的时候,就根据next[]的值移动子串到相应位置去和模板串匹配。

这里模拟一下匹配过程,i表示模板串的当前匹配位置,j表示子串的当前匹配位置,初始i=0,j=0;模板串p[],子串s[]

a!=c           --->          i++                                                      i=1,j=0

a!=b          --->           i++                                                      i=2,j=0

a!=b          --->           i++                                                      i=3,j=0

a!=b          --->           i++                                                      i=4,j=0

a==a         --->           i++,j++                                              i=5,j=1

b!=a          --->          i保持不变,j=next[j],跳转       i=5,j=0

a==a          --->         i++,j++                                              i=6,j=1

b==b          --->         i++,j++                                              i=7,j=2

a==a          --->         i++,j++                                              i=8,j=3

b==b          --->         i++,j++                                              i=9,j=4

a==a          --->         i++,j++                                              i=10,j=5

j>=strlen(s)        匹配结束   , 返回可以匹配的首地址  return j-i+1

      

#include<iostream>
#include<string.h>
using namespace std;
char p[100],s[100];
int next1[100];
void get_next(char *s,int *next1)
{
    int m=strlen(s);//子串的长度
    int j=0;//当前匹配的位置
    int k=-1;//失配的时候要跳转的位置(也是最长公共前后缀的长度)
    next1[0]=-1;
    while(j<m)
    {
        if(k==-1||s[j]==s[k])
            next1[++j]=++k;
        else
            k=next1[k];
    }
}
int kmp(char *p,char *s)//p是模板串,s是子串
{
    int i=0,j=0;
    int n=strlen(p);
    int m=strlen(s);
    while(i<n&&j<m)
    {
        if(j==-1||p[i]==s[j])
        {
            i++;
            j++;
        }
        else
            j=next1[j];
    }
    if(j>=m)//s串比较完毕
        return i-m+1;
    else
        return -1;
}

int main()
{
    cin>>p>>s;
    get_next(p,next1);
    for(int i=0;s[i];i++)
        cout<<"next["<<i<<"]="<<next1[i]<<endl;
    cout<<"从第"<<kmp(p,s)<<"个字符开始匹配"<<endl;//返回的是开始匹配的第几个字符,不是位置
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!