KMP--字符串匹配(前缀数组)

算法背景:

Knuth–Morris–Pratt algorithm

数据结构:

next数组 +  。。

算法原理:

预处理匹配串(匹配串与自己匹配)得到失配数组

没了。

得到失配数组NEXT的函数:

void getnext(char *p)//匹配串
{
    int m=strlen(p);//匹配串的长度m
    int k=-1,cur=0;//k是第二匹配串的下标,也是next的下标,cur是第一匹配串的下标
    nxt[cur]=k;//初始化next的第0个元素为-1
    while(cur<m)//第一匹配串的下标小于m
    {
        if(k==-1||p[cur]==p[k])//回到了第二匹配串的原点或者第一匹配串的第cur个字符和第二匹配串的第k个字符相同
            nxt[++cur]=++k;//标记next-->之前的最长前后缀长度
        else
            k=nxt[k];//否则,向前回溯,在回溯的同时,也相当于把第二匹配串向后移动k-next[k]个单位
    }
}

kmp主体:

void kmp(char *t,char *p)//文本串,匹配串
{
    int n=strlen(t);//文本串长度
    int m=strlen(p);//匹配串长度
    int k=0,cur=0;//k是匹配串下标,cur是匹配串的下标
    getnext(p);//找到失配数组
    while(cur<n)//不用讲了
    {
        if(k==-1||t[cur]==p[k])//回到了匹配串的远点,或者两个串的下标对应相等
        {
            k++;//下标+1
            cur++;//下标+1
        }
        else
            k=nxt[k];//否则,匹配串往前回溯,和使匹配串往后移动k-next[k]个单位同理
        if(k==m)//匹配完了 
            cout<<cur-m<<endl;//输出匹配成功的起始位置,自然是cur-m了  
    }
    return;
}

CODE:

#include <iostream>
#include <cstring>
using namespace std;
char p[100],t[100];
int nxt[100];
void getnext(char *p)
{
    int m=strlen(p);
    int k=-1,cur=0;
    nxt[cur]=k;
    while(cur<m)
    {
        if(k==-1||p[cur]==p[k])
            nxt[++cur]=++k;
        else
            k=nxt[k];
    }
}
void kmp(char *t,char *p)
{
    int n=strlen(t);
    int m=strlen(p);
    int k=0,cur=0;
    getnext(p);
    while(cur<n)
    {
        if(k==-1||t[cur]==p[k])
        {
            k++;
            cur++;
        }
        else
            k=nxt[k];
        if(k==m)
        {
            cout<<cur-m<<endl;
            k=-1;
            cur-=1;
        }
    }
    return;
}
int main()
{
    cin>>t>>p;
    kmp(t,p);
}
/*
abacabababab
abab
*/

算法解释:

1.整个算法的大致和求next数组的基本原理都在:

一、阮一峰–KMP

二、KMP-有意思

ORZ….

添加一个题集:

题集

 

一个简单优化:

void getnext(char *p)
{
    int m=strlen(p);
    int k=-1,cur=0;
    nxt[cur]=k;
    while(cur<m)
    {
        if(k==-1||p[cur]==p[k]) 
        {
            if(p[++cur]!=p[++k])
                nxt[cur]=k;
            else
                next[cur]=next[k];//在这里优化,我们将避免愚蠢的错误和明显的不匹配
        }  
        else
            k=nxt[k];
    }
}

解释优化的原理:

网站:优化原理

关于kmp的返回值问题:

一、

返回所有(包括重叠)的模式串的起始位置:cur-m。//非常神奇,所以搞不明白

code:

if(k==m)
{ 
    cout<<cur-m<<endl;
}

二、

返回所有(不包括重叠)的模式串的起始位置。

if(k==m)
{ 
    cout<<cur-m<<endl;
    k=-1;
    cur--;
}

太简单了,不解释了

处理next数组当作周期串:
 

if(k==-1||p[cur]==p[k])
{
    nxt[++cur]=++k;
    zhouqi[cur]=cur-nxt[cur];//这里的周期就是字符串的最小循环节,求法:cur-nxt[cur]
}

在这里,还要提醒一点,next是求的前缀数组,而后缀数组是HASH做法,

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/Ivanzn/article/details/82019603
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞