从BF到KMP

一、BF

从主串S的第pos个字符起和模式串的第一个字符比较之,若相等,则继续比较后续字符;否则从主串的下一个字符起再重新和模式T的字符比较之。依此类推,直至模式T中的每一个字符依次和主串S中的一个连续的字符串序列相等,则称匹配成功,函数值为和模式T中的第一个字符相等的字符在主串S中的下标;否则称匹配不成功,函数值为-1。(下标是从0开始的)。

#include<stdio.h>   //printf()                                                  
#include<assert.h>  //exit() assert()
#include<string.h>
int bf(char *S, char *T, int pos){
    assert(S != NULL && T != NULL);
    int i = pos;
    int j = 0;
    while(i < strlen(S) && j < strlen(T)){
        if(S[i] == T[j]){
            ++i;
            ++j;
        }   
        else
        {   
            i = i - j + 1;
            j = 0;
        }   
    }
    return j >= strlen(T)? i-j : -1; 
}

int main(){
    char s[] = {"abcababcabc"};
    char t[] = {"abcabc"};
    int res;
    res = bf(s,t,3);
    printf("%d\n", res);
    exit(0);
}                                 
图1  linux下运行结果

 二、KMP算法 

不谈原理,只谈如何理解和使用。

图2 情形1

去掉已经有确切结果的比较。观察图2,S串和P串,在i=5和j=5处失配。按照BF算法的思想,i将回退到i-j+1的位置,j清零。这带来一个问题:S[1] != P[0]故主串移动一字符,重新匹配而S[2]!=P[0](这两处比较是无用的,因为肯定不相等);再重新匹配S[3]=P[0],S[4]=P[1],但是这两个字符相等是可以推导出来的(故这两个字符的比较也是无用的),最理想的比较应该是S[5] ?= P[3]!这一点将在KMP中巧妙实现。

图3  情形2

观察图3,6号位置的字符b对应的值为1需要说明:0号位置和5号位置的字符相同,除此之外,就没有了,故而在子串[0...6]中,最长头尾真子串长度为1,将1和6号位置的字符b对应。研究7号位置字符对应的数值的时候,因为6号位置所对应的数值为1,我们就需要判断串中1号位置和6号位置字符是否相等,相等的话,在前面一个字符对应的数值的基础上加1。不相等的情况稍后讨论!

图4  情形3

观察图4,此时9号位置字符不等于6号位置字符,需要一直向前回溯,直到到达尽头。故13号位置的字符对应的数值为0。这属于不相等情况中的最后也未找到的情况。 

图5 情形4

观察图5,最终找到了!!!

#include<string.h>  //memset()                                                  
#include<stdio.h>   //printf()
#include<assert.h>  //assert()
#include<malloc.h>  //malloc()

void get_next(const char *T, int next[]){
    assert(T != NULL);
    int n = strlen(T);  
    int i = 2;
    int k = 0;  //k = next[i-1] == next[0] == 0;
    next[0] = -1; 
    next[1] = 0;
    while(i < n){ 
        while(k > -1 && T[i-1] != T[k]){
            k = next[k];
        }   
        next[i++] = ++k;
    }   
}

int kmp(const char* S, const char* T, int pos){
    assert(S != NULL && T != NULL);
    int slen = strlen(S);
    int tlen = strlen(T);
    int i = pos;
    int j = 0;
    int *next = (int *)malloc(sizeof(int)*tlen);
    assert(next != NULL);                                                       
    memset(next, 0, sizeof(int)*tlen);
    while(i < slen && j < tlen){
        if(j == -1 || S[i] == T[j]){
            i++;
            j++;
        }
        else{
            j = next[j];
        }
    }
    free(next);
    return j >= tlen ? i-j : -1;
}

 代码不多,但是需要逐行去体会!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值