KMP算法解析以及手工计算next函数方法

KMP算法的原则:每当匹配不相等时,主串中i指针不变,模式串中j指针移动到恰当的位置。

本博客仍旧采用如下定长顺序存储,数组的0号单元用于存放字符串长度。

#define MAXSTRLEN 255//宏定义串的最大长度MAXSTRLEN为255
typedef unsigned char SString[MAXSTRLEN + 1];//定义SString为无符号字符数组类型,数组长度为256

#KMP算法解析

1.用Si表示主串中第i个字符,用Pj表示模式串中第j个字符;

   当Si与Pj匹配不相等时,i不变,j变为k。

(i不变对应了主串中i指针不回溯的原则,j变为k对应了next函数,即k=next[j])

2.若要让Si与Pk继续匹配,必须满足的条件是P1....Pk-1与Si-k+1....Si-1匹配相等

3.已知P1....Pj-1与Si-j+1....Si-1匹配相等,可推出Pj-k+1....Pj-1与Si-k+1....Si-1匹配相等

4.所以若要让Si与Pk继续匹配,必须满足P1....Pk-1=Pj-k+1....Pj-1

*即必须满足前k-1个字符与后k-1个字符相等

5.又因为k越大,节省的比较次数就越多,所以选择满足条件*的最大k值

**补充说明:当j=1时,Si与Pj就不匹配时,规定k=0

 

#演示手工计算next值

j           1 2 3 4 5 6 7 8

模式串 a b a a b c a c

next[j]

当j=1时,根据定义k=0;

当j=2时,利用条件*,观察字符串a,可知k-1=0,k=1;

当j=3时,利用条件*,观察字符串ab,可知k-1=0,k=1;

当j=4时,利用条件*,观察字符串aba,可知k-1=1,k=2;

当j=5时,利用条件*,观察字符串abaa,可知k-1=1,k=2;

当j=6时,利用条件*,观察字符串abaab,可知k-1=2,k=3;

当j=7时,利用条件*,观察字符串abaabc,可知k-1=0,k=1;

当j=8时,利用条件*,观察字符串abaabca,可知k-1=1,k=2.

next[j]:1122312

#由此KMP算法可以由暴力匹配算法改进而得出

int Index_KMP(SSTring S,SSTring T,int pos)//利用KMP算法求模式串T在主串S中第pos个字符之后的第一个出现位置
{
    int i=pos;
    int j=1;
    while(i<=S[0]&&j<=T[0])
    {
        if(j==0||S[i]==T[j])//加上j==0,巧妙解决了Si与P1不匹配时的情况,使得Si+1与P1继续比较
        {
            i++;
            j++;
        }
        else
            j=next[j];//运用了KMP算法核心原则,当Si与Tj不等时,i不变,j变为k(即next[j])
    }
    if(j>T[0]) return i-T[0];
    else return 0;
}

#get_next函数解析

1.由定义得,next[1]=0;

2.设next[j]=k

根据条件*可知P1....Pk-1=Pj-k+1....Pj-1;

若Pk=Pj,则由P1....Pk=Pj-k+1....Pj,得出next[j+1]=k+1,即next[j+1]=next[j]+1;

3.若Pk不等于Pj时,仿照KMP算法,将整个模式串既看成主串又看成模式串

Pj-k+1=P1

Pj-k+2=P2

...

Pj-1=Pk-1

当Pj不等于Pk时,j不变,k变为next[k](设k1=next[k]);

若Pj=Pk1,则根据条件*可推出P1....Pk1=Pj-k1+1....Pj;

next[j+1]=k1+1;

若Pj不等于Pk1,可继续按此方法推下去,求出Kn.

4.若没有满足条件*与Pj=Pkn的Kn,则next[j+1]=1.

void get_next(SSTring T,int next[])
{

    next[1]=0;//由定义得到的前提条件
    int j=1;
    int k=0;//根据假设next[j]=k设置j,k初值
        
        while(j

KMP算法解析以及手工计算next函数方法_第1张图片

#本博客参考了《数据结构(C语言版)》(严蔚敏,吴伟民编著)

 

 

 

你可能感兴趣的:(算法与数据结构)