kmp(含水分)

KMP字符串匹配算法1


KMP字符串匹配算法1

KMP字符串匹配算法2


KMP字符串匹配算法2

在这里插入图片描述

prefix[0] = 0;
0 AB
1 ABA
2 ABAB
0 ABABC
1 ABABCA
2 ABABCAB
3 ABABCABA
1 ABABCABAA

如果下个位置相等就

if(p[len]==p[i])
len++
prefix[i] = len;
void prefix_table(char pattern[],int prefix[],int n){
   prefix[0] = 0;
   int len = 0;
   int i = 1;
   while (i<n){
       printf("i=%d len=%d\n",i,len);
       //相等
       if(pattern[i] == pattern[len]){
           len++;
           prefix[i]=len;
           i++;
       }
       //不相等
       else{
           if(len>0)
                len = prefix[len-1];
           else {
               prefix[i] = 0;//此时len = 0;
               i++;
           }
       }
   }
}

中途的元素不匹配用p[-1]来和 它对齐。
在这里插入图片描述

if(j==-1){
     i++;
     j++;
}

匹配成功一个,再去找下一个pattern[ ],j的取值:

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;
void move_prefix_table(int prefix[],int n){
    int i;
    for(i=n-1;i>0;i--){
        prefix[i] = prefix[i-1];
    }
    prefix[0] = -1;
}
void prefix_table(char pattern[],int prefix[],int n){
   prefix[0] = 0;
   int len = 0;
   int i = 1;
   while (i<n){
       printf("i=%d len=%d\n",i,len);
       //相等
       if(pattern[i] == pattern[len]){
           len++;
           prefix[i]=len;
           i++;
       }
       //不相等
       else{
           if(len>0)
                len = prefix[len-1];
           else {
               prefix[i] = 0;//此时len = 0;
               i++;
           }
       }
   }
}
void kmp_search(char text[],char pattern[]){
    int n=strlen(pattern);
    int* prefix = (int*)malloc(sizeof(int)*n);
    prefix_table(pattern,prefix,n);
    move_prefix_table(prefix,n);
    //text[i] len(text) = m
    //pattern[j] len(pattern) = n;
    int i = 0;
    int m =strlen(text);
    int j = 0;
    while(i<m){
        if(j==n-1 && text[i] == pattern[j]){
            printf("Find pattern at %d.\n",i-j);
            j = prefix[j];
        }
        if(text[i]==pattern[j]){
            i++;
            j++;
        } else{
            j = prefix[j];
            if(j==-1){
                i++;
                j++;
            }
        }
    }
}
int main(){
//    char pattern[] = "ABABCABAA";
//    int prefix[9];
//    int n=9;
//    prefix_table(pattern,prefix,n);
//    move_prefix_table(prefix,n);
//    int i;
//    for(int i=0;i<n;i++){
//        printf("%d ",prefix[i]);
//    }
    char pattern[] = "ABABCABAA";
    char text[] = "ABABABCABAABABABABABCABAA";
    kmp_search(text,pattern);
    return 0;
}

此后不用看
但是问题是本应该是和p[1]来对齐这个地方,但是上面用p[3]来对齐,我们发现p[3]->p[1]->p[0],我们发现p[3]->p[1],解决办法就是我觉得可以prefix数组多增加一位,然后用p[3]来对齐这个。
这个prefix数组多加了prefix【0】=-1,会把最后一位给抹除掉,可以申请prefix为n+1位。这样的话,当找到一个匹配的字符串之后,再去找下一个匹配字符串的时候,j = prefix【j+1】(相对原先的j = prefix【j】)效率高一点。

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;
void move_prefix_table(int prefix[],int n){
    int i;
    for(i=n-1;i>0;i--){
        prefix[i] = prefix[i-1];
    }
    prefix[0] = -1;
}
void prefix_table(char pattern[],int prefix[],int n){
   prefix[0] = 0;
   int len = 0;
   int i = 1;
   n = n-1;
   while (i<n){
       printf("i=%d len=%d\n",i,len);
       //相等
       if(pattern[i] == pattern[len]){
           len++;
           prefix[i]=len;
           i++;
       }
       //不相等
       else{
           if(len>0)
                len = prefix[len-1];
           else {
               prefix[i] = 0;//此时len = 0;
               i++;
           }
       }
   }
}
void kmp_search(char text[],char pattern[]){
    int n=strlen(pattern);
    int* prefix = (int*)malloc(sizeof(int)*(n+1));
    prefix_table(pattern,prefix,n+1);
    move_prefix_table(prefix,n);
    //text[i] len(text) = m
    //pattern[j] len(pattern) = n;
    int i = 0;
    int m =strlen(text);
    int j = 0;
    while(i<m){
        if(j==n-1 && text[i] == pattern[j]){
            printf("Find pattern at %d.\n",i-j);
            j = prefix[j+1];
        }
        if(text[i]==pattern[j]){
            i++;
            j++;
        } else{
            j = prefix[j];
            if(j==-1){
                i++;
                j++;
            }
        }
    }
}
int main(){
    char pattern[] = "ABABCABAA";
    char text[] = "ABABABCABAABABABABABCABAA";
    kmp_search(text,pattern);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jieshenai

为了遇见更好的文章

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值