KMP算法

背景:设两个串s和t,串t的定位就是在串s中找到一个与t相同的子串。S为目标串,t为模式串,因此串定位查找也叫模式匹配。KMP算法是一个效率较高的针对模式匹配的算法。

详解
1.
从模式串中提取加速匹配的信息,即next表

在KMP算法中,通过分析模式串t从中提取加速匹配的有效信息。这种信息是对于串t的每个字符t[j](0<=j<=m-1)存在一个整数k(k < j),使模式串t中开头的k个字符(t[0],t[1],… ,t[k-1])依次与t[j]的前面k个字符(t[j-k],t[j-k+1],… ,t[j-1]且j-k >= 1)相同。如果k有多个,则取最大的一个。模式串t中每个位置j的字符都有这种信息,采用next数组表示:next[j] = MAX{ k }。

解释说来,当j = 0,next[0] = -1;

当j=1,串t在1 ~ j-1上没有字符,属于其他情况,next[1] = 0;

当t[k] = t[j],说明t[0],t[1],… ,t[k] = t[j-k],t[j-k+1],… ,t[j],则next[j] = k,next[j+1] = k+1;即0往后,j-k往后寻找相同字符的个数为k(包括0和j-k,但不包括k和j);

当t[k] != t[j],那么要寻找t[j]前一个长度更短的子串和开头字符起的子串相同,设k1 = next[k],若t[k1] = t[j],即0往后,j-k1往后寻找相同字符的个数为k1,则next[j]=k1;否则依此类推寻找更短的子串,直到next[j+1] = 0,因为next[j+1] = k1+1,k1+1是子串的长度。

求模式串t的next数组,算法如下:

void GetNext(SqString t,int next[])
{
        int j,k;
        j=0,k=-1;          //j扫描串t,k记录t[j]之前与t开头相同的字符的个数
        next[0]=-1;
        while(j<t.length-1)
        {
                if(k == -1||t.data[j] == t.data[k])
                {
                        j++;
                        k++;
                        next[j]=k;
                }
                else
                {
                        k=next[k];    //k回退 
                     
                }
        }
}

2.
KMP算法的模式匹配过程

next表可以用来消除主串指针的回溯,减少匹配次数。

以目标串s = ”aaaaab”,模式串t = ”aaab”为例,第一次匹配从i= 0,j = 0开始,失配处为i = 3,j = 3,尽管匹配失败,也得到部分匹配信息,s[1]s[2]= t[1]t[2],next[3]=2。此时第二次匹配可从i = 3,j = next[3] =2开始,即主串指针i不变,模式串t右滑 j – next[j] 个位置,再进行比较。

KMP算法如下:

int KMP(SqString s,SqString t)
{
     int i=0,j=0,next[Maxsize];
     GetNext(t,next);
     while(i<s.length&&j<t.length)
     {
             if(j==-1||s.data[i]==t.data[j])
             {
                     i++;
                     j++;
             }

             else
             {
                     j=next[j];    //i不变,j后退,模式串右滑 
             }
     }
     if(j>=t.length)

     {
            return (i-t.length);    //匹配成功 
     }
     else
     {
             return -1;     //匹配失败 
     }
}

 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值