zoukankan      html  css  js  c++  java
  • KMP算法初探

    [edit by xingoo]

    kmp算法其实就是一种改进的字符串匹配算法。复杂度可以达到O(n+m),n是参考字符串长度,m是匹配字符串长度。

    传统的算法,就是匹配字符串与参考字符串挨个比较,如果相同就比较下一个,如果不相同,就返回上一次的结果,再重新比较。

    如图1 如果失败则字符串会重新用S(参考字符串)的第二个,与T(匹配字符串)的第一个比较,知道全部符合查找,或找不到为止。

    此时发现S[5] != T[5],因此用S[1]与T[0]进行比较。

    此时发现S[1]!=T[0],因此用S[2]与T[0]比较。

    此时,仍然不相等,继续后移。

    此时,S[3] == T[0],继续比较,发现所有T元素都在S中找到,满足查找,返回开始匹配的下标3.

    传统代码

     1 int old_index(char * S,char * T){
     2     int i=0;
     3     int j=0;
     4     while(i<strlen(S) && j<strlen(T)){
     5         if( S[i] == T[j] ){
     6             ++i;
     7             ++j;
     8         }
     9         else{
    10             i = i-j+1; //上一次的下一个
    11             j=0;
    12         }
    13     }
    14     if(j == strlen(T))
    15         return i-strlen(T);
    16     else
    17         return -1;
    18 }

    这种比较忽略了一个问题,就是在T中,abcabx,第一个字符串因为不跟第二个,第三个一样,因此,在一开始的匹配中,可以直接跳过比较,直接从S的第三个元素开始比较。这里就涉及到一个概念:最短子串对称匹配。

    首先,初始化,当j=0时,next(j)=-1;

    当j=1时,字符串0到j-1,只有"a",因此 next(j) = 0;

    当j=2时,字符串0到j-1,字符串为"ab",因此next(j) = 0;

    当j=3时,字符串0到j-1,字符串为"abc",因此next(j) = 0;

    当j=4时,字符串0到j-1,字符串为"abca",此时,前缀a在末尾出现,因此next(j) = 1;

    当j=5时,字符串0到j-1,字符串为"abcab",此时,前缀ab在末尾出现,因此next(j) = 2;

    最后得到next的数组为"-1 0 0 0 1 2"。

    按照这个方法:

    ababab的next数组为"-1 0 0 1 2 3 4"

    这里面,当j=5时,字符串"ababa",前缀是"aba",后缀也是"aba",因此next值为3.

    计算next数组详细代码

    void getNext(char * T,int *next){
        int i,j;
        i=0;
        j=-1;
        next[0]=-1;
        while(i<strlen(T)){
            if(j == -1 || T[i] == T[j]){
                ++i;
                ++j;
                next[i] = j;
            }
            else{
                j = next[j];
            }
        }
    }

    kmp匹配代码

    int kmp(char* S,char * T){
        int i=0;
        int j=0;
        int next[MAX];
        getNext(T,next);
        while(i<strlen(S) && j<strlen(T)){
            printf("i %d-%c j %d-%c
    ",i,S[i],j,T[j]);
            if(j==0 || S[i]==T[j]){
                ++i;
                ++j;
            }else{
                j = next[j];
                printf("j back to %d
    ",j);
            }
        }
        if(j == strlen(T))
            return i-strlen(T);
        else
            return 0;
    }

    全部代码

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #define MAX 20
     5 
     6 void getNext(char * T,int *next);
     7 int kmp(char * S,char * T);
     8 int old_index(char * S,char * T);
     9 
    10 int main()
    11 {
    12     char * s = "acabbabababc";
    13     char * t = "ababab";
    14 
    15     //printf("the pos is:%d
    
    ",old_index(s,t));
    16     //printf("the pos is:%d
    
    ",old_index(m,t));
    17     //printf("the pos is:%d
    
    ",old_index(n,t));
    18     printf("the pos is:%d
    ",kmp(s,t));
    19     return 0;
    20 }
    21 
    22 void getNext(char * T,int *next){
    23     int i,j;
    24     i=0;
    25     j=-1;
    26     next[0]=-1;
    27     while(i<strlen(T)){
    28         if(j == -1 || T[i] == T[j]){
    29             ++i;
    30             ++j;
    31             next[i] = j;
    32         }
    33         else{
    34             j = next[j];
    35         }
    36     }
    37 }
    38 
    39 int kmp(char* S,char * T){
    40     int i=0;
    41     int j=0;
    42     int next[MAX];
    43     getNext(T,next);
    44     while(i<strlen(S) && j<strlen(T)){
    45         printf("i %d-%c j %d-%c
    ",i,S[i],j,T[j]);
    46         if(j==0 || S[i]==T[j]){
    47             ++i;
    48             ++j;
    49         }else{
    50             j = next[j];
    51             printf("j back to %d
    ",j);
    52         }
    53     }
    54     if(j == strlen(T))
    55         return i-strlen(T);
    56     else
    57         return 0;
    58 }
    59 int old_index(char * S,char * T){
    60     int i=0;
    61     int j=0;
    62     while(i<strlen(S) && j<strlen(T)){
    63         if( S[i] == T[j] ){
    64             ++i;
    65             ++j;
    66         }
    67         else{
    68             i = i-j+1; //上一次的下一个
    69             j=0;
    70         }
    71     }
    72     if(j == strlen(T))
    73         return i-strlen(T);
    74     else
    75         return -1;
    76 }
    View Code

    运行结果

  • 相关阅读:
    用栈实现队列
    “非常规”的漏洞挖掘思路与技巧-请求参数加密,js接口- 漏洞定级评分的标准与关注点-违规测试标准详解
    【linux 文件管理】2-文件目录命令
    EHC
    kali linux高级渗透测试第七课
    maltego CE社区版-Domain与DNS name
    name servers-域名服务器
    【linux 文件管理】1-文件目录结构
    web应用安全自学指南
    kali linux高级渗透测试第六课
  • 原文地址:https://www.cnblogs.com/xing901022/p/3535888.html
Copyright © 2011-2022 走看看