KMP


Code:

//KMP
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
int next[maxn];
void GetNext(char *P) ;  //未改进的KMP,next[i]数组中代表的值是如果当前i位置匹配不成功, 指针指到模式串的哪一个位置(下标)
void GetNNext(char *P);  //改进的KMP
void Find(char *T, char *P)
{
    int len1 = strlen(T), len2 = strlen(P);
    GetNext(P);
//    for(int i = 0; i < len2 ; i++)
//        cout << next[i] << " ";
//    cout << endl;
    GetNNext(P);
    int j = 0;
    for(int i = 0; i < len1; i++)
    {
        while(j && P[j] != T[i])  j = next[j];
        if(P[j] == T[i])  j++;
        if(j == len2)
        {
            printf("找到了: ");
            printf("%d\n", i-len2+1);
            return ;
        }
    }
    printf("没找到\n");
    return ;
}

/*
字符串匹配的原理:P[0]匹配不成功,只能让指向被查找串的指针后移,找到一个能和模式串第一个对应的字符
   和其中某一个匹配不成功,说明前面已经有一部分匹配成功了,让指针按照所预先处理的next值进行移动
   某一个字符串匹配成功, 指向模式串和查找串的指针都向后移动
   指向寻找串的指针越界,说明没找到,指向模式串的指针越界,说明找到了 当前查找串的指针 - 模式串长度 + 1
   就是匹配成功的第一个位置的下标
KMP算法的核心: next数组的求解(递推法求解)
    先赋初值:和第一个匹配不成功, 那只能向后找喽 next[0] = 0;
              和第二个匹配不成功, 也只能从头开始找,因为和第二个不匹配,也就是再去和第一个配,也就是从头开始找了
              和后面的不匹配 !!!! KMP的精华:
              开始向回找,找看有没有能够相等的前缀 while(j && P[i] != P[j]) j = next[j]; 这样一直向后退
              知道有一个不满足的,然后可以用它来计算它的下一个,
              如果P[i] == P[j] next[i+1] = j+1; 
              如果P[i] != P[j] next[i+1] = 0; 前功尽弃
              为什么是下一个呢: 因为我们所寻找的一直都是它前面的那一部分
*/
void GetNext(char *P)
{
    int len = strlen(P);
    next[0] = 0, next[1] = 0;
    for(int i = 1; i < len; i++)
    {
        int j = next[i];
        while(j && P[i] != P[j])
            j = next[j];
        next[i+1] = P[i] == P[j] ? j+1 : 0;   //如果不对直接返回开头
    }
}

void GetNNext(char *P)
{
    int len = strlen(P);
    for(int i = 1; i < len; i++)
    {
        if(P[i] == P[next[i]])
            next[i] = next[next[i]];
    }
}

int main()
{
    char Text[10000], Purpose[100000];
    memset(next, 0, sizeof(next));
    scanf("%s", Text);
    scanf("%s", Purpose);
    Find(Text, Purpose);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值