KMP(模板)


 

kmp算法是解決單模匹配問題的算法,難點在於求next[]數組

求next[]數組:對於子串的所有前綴子串的最長公共前后綴的長度,就是next[]數組的值

 

首先,要了解兩個概念:"前綴"和"后綴"。 "前綴"指除了最后一個字符以外,一個字符串的全部頭部組合;"后綴"指除了第一個字符以外,一個字符串的全部尾部組合。如下圖所示:


下面再以”ABCDABD”為例,進行介紹:

”A”的前綴和后綴都為空集,共有元素的長度為0;

”AB”的前綴為[A],后綴為[B],共有元素的長度為0;

”ABC”的前綴為[A, AB],后綴為[BC, C],共有元素的長度0;

”ABCD”的前綴為[A, AB, ABC],后綴為[BCD, CD, D],共有元素的長度為0;

”ABCDA”的前綴為[A, AB, ABC, ABCD],后綴為[BCDA, CDA, DA, A],共有元素為”A”,長度為1;

”ABCDAB”的前綴為[A, AB, ABC, ABCD, ABCDA],后綴為[BCDAB, CDAB, DAB, AB, B],共有元素為”AB”,長度為2;

”ABCDABD”的前綴為[A, AB, ABC, ABCD, ABCDA, ABCDAB],后綴為[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的長度為0。

 

eg:主串為cbbbaababac  子串為ababac

初始化next[0]=-1;

         子串的最長公共前后綴長度

a                           -->0                             next[1]=0            a的前綴為空,后綴也為空,共有元素的長度為0

ab                        -->0                             next[2]=0             ab前綴為[a],后綴為[b],共有元素的長度為0

aba                      -->1                             next[3]=1             前綴為[a,ab],后綴為[a,ba],共有元素的長度為1

abab                   -->2                              next[4]=2             前綴為[a,ab,aba],后綴為[b,ab,bab],共有元素的長度為2

ababa                -->3                               next[5]=3             前綴為[a,ab,aba,abab],后綴也為[a,ba,aba,baba],共有元素的長度為3

next[i]數組的作用是在當子串字母s[i]在和主串字母p[j]失配的時候,next[i]數組提供一個值,子串整體移動( i-next[i] )個位置,繼續用s[next[i]]去和主字母p[j]匹配

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

子串下標:                        0    1   2   3   4   

                                               a    b   a   b   a 

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

 

這里解釋一下:當子串和主串失配的時候,就根據next[]的值移動子串到相應位置去和主串匹配。當子串next[]值為-1的時候,主串的當前匹配位置后移一個字母

這里模擬一下匹配過程,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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM