KMP算法--C/C++

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

很明显,我们可以看出这个算法时间复杂度很低,如果用传统方式,那么时间复杂度为n2,这有时候字符串太长,效率就很低。

KMP算法的核心在于,如何创建next数组,在此我简单说下:
如abcabcb这个pattern字符串。

我们需要寻找前缀与后缀

初始next[0] = -1;表示next数组头
1. a 前缀{空},后缀{空},next[1]=0
2. ab 前缀{a},后缀{b} ,next[2]=0
3. abc 前缀{a,ab},后缀{c,bc} ,next[3]=0
4. abca 前缀{a,ab,abc} 后缀 {a,ca,bca} next[4]=1 此时公共前后缀长度为1
5. abcab 前缀{a,ab,abc,abca} 后缀**{b,ab,cab,bcab}**next[5]=2 此时公共前后缀长度为2
6. abcabc 前缀{a,ab,abc,abca,abcab} 后缀{c,bc,abc,cabc,bcabc} next[6]=3 此时公共前后缀长度为3

分析:通过当前角标前一个的子串前后缀个数+1,即为当前next数组的值 next[i+1] = j+1 (j为前一个子串的前后缀个数)即用i推出i+1的next[i+1]的值.

所以next数组为{-1,0,0,1,2,3}

具体代码如何实现:

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
int next[100];//存储next数组

void getNext(string s1){

    next[0] = -1;//和严蔚敏老师的略不同,我从下标0开始,严蔚敏老师从1开始 
    int i = 0,j = -1;
    while(i<s1.length()){

        if(j==-1||s1[i]==s1[j])
            next[++i] = ++j;//++i处的next值为之前子串中,前后缀匹配个数+1  即next[i+1] = j+1;因为i和j要自增,所以写成++i和++j
        else
            j = next[j];//如果不匹配,那么j的值进行前移,寻找与i处匹配的字符,如果都不匹配,则到j=-1为止。 
    }
    for(int i = 0;i<s1.length();i++)
        cout<<next[i]<<" ";
}

void KMP(string s1,string s2){//左为待匹配串,右为模式串 
    int i = 0,j = -1;
    while(i<s1.length()){
        if(j==-1||s1[i]==s2[j]){
            i++;j++; 
        }
        else{
            j = next[j];//i始终大于j
        }

        if(j==s2.length()){
            //匹配结束
            cout<<"第"<<i-j+1<<"个字符位置处开始匹配"<<endl;
            i = i-j+1;//从当前匹配为止的下一个字符开始,再进行匹配,即aaaa中有3个匹配aa的 
             j = -1;
        }
    }

} 

int main(){

    string s1 = "abcdeabcdssaaabcabcabcabdxxcvxzvadf";//待匹配串 
    string s2 = "abcabcb";//模式串 
    getNext(s2);
    KMP(s1,s2);
    return 0;
} 

之前写的KMP是错误的,后来学习数据结构在发现学了一个错误的算法、在此抱歉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值