KMP算法

本文深入讲解了KMP算法的工作原理及实现过程,并提供了完整的C++代码示例。通过本文,读者可以了解如何构造next数组以及如何利用该数组提高模式匹配效率。

这个算法很经典,我花了一个下午加一个晚上才搞明白!我佩服想出这个算法的人精湛而严密的数学思维!向他们致敬!这个算法,应该是我到目前为止见过的最美丽的算法了。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
void get_next(char T[],int next[],int len_T)//获取next数组的方法,T[]子串
{
    int i,j;//同样定义两个指针
    i=2;//i在后面,i现在虽然为2,实则考察的是i+1,即3,请读者自行领会
    j=1;//j在前面
    next[1]=0;//这是必然的
    next[2]=1;//这是必然的
    while(i<len_T)//注意,这里是<而不是<=,因为每到i,其实是考察的i+1的next的值!
    {
        if(T[i]==T[j])//如果相等,就++,然后next[i]就是j
        {
            i++;
            j++;
            next[i]=j;//这个赋值语句暗藏很多数学道理,读者请自行领悟,具体证明见严蔚敏83页公式推导论证
        }
        else
        {
            if(j==1)//说明j已经回溯到尽头了,此时j为1,因此i必须前进一格,对应于严蔚敏81页公式4-5中的其他情况,此时找不到这个k,因此置next[i]为1
            {
                i++;
                next[i]=1;
            }
            else//这个说明还没有回溯到尽头,所以就继续回溯呗!
                j=next[j];
        }
    }
}
int KMP(char S[],char T[],int pos,int next[],int len_S,int len_T)//KMP算法主体部分,S为主串,T为子串,pos是规定从主串下标为pos的地方开始模式匹配
{
    int i,j;//i,j分别为主串和子串的指针
    i=pos,j=1;
    while(i<=len_S&&j<=len_T)//遍历主串和子串
    {
        if(S[i]==T[j])//如果相等,i和j都++
        {
            i++;
            j++;
        }
        else//如果不等,就要看j的值了
        {
            if(j==1)//如果此时回溯到尽头,i就必须++
                i++;
            else
                j=next[j];//否则就回溯呗
        }
    }
    if(j>len_T)//这个要理解,如果我大于T[0],说明我此时已经全部匹配成功啦,i就回退T的长度,就是匹配成功字符串的第一个数组下标
        return i-len_T;
    return -1;//匹配不成功就返回-1
}
int main()
{
    char c,S[100],T[100];
    int next[100],ret,i,len_S,len_T;
    i=1;
    cout<<"请输入主串,以回车结束!"<<endl;
    /*下标从1开始进行输入S*/
    c=getchar();
    while(c!='\n')
    {
        S[i++]=c;
        c=getchar();
    }
    S[i]='\0';//C语言基础知识
    len_S=i-1;//考察字符串基本功
    /*下标从1开始进行输入T*/
    i=1;
    cout<<"请输入子串,以回车结束!"<<endl;
    c=getchar();
    while(c!='\n')
    {
        T[i++]=c;
        c=getchar();
    }
    T[i]='\0';
    len_T=i-1;
    get_next(T,next,len_T);
    ret=KMP(S,T,1,next,len_S,len_T);
    if(ret!=-1)
        cout<<"首次出现子串的下标为"<<ret<<"!"<<endl;
    else
        cout<<"找不到!"<<endl;
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值