KMP字符串查找

KMP算法
KMP字符串查找算法的目的是减少不必要的比较次数,举个简单的例子,从字符串A:"abcdeabcdfg"中查找字符串B:"abcdf"。
使用普通的查找法查找字符串的步骤是这样的:
先拿A[0:4]分别与B对应位置的字母比较,如果不相等则拿A[1:5]与B比较,依次类推,直到结束。
而KMP算法先分析要朝朝的字符串,以B为例,由于a与后面的四个字节都不相同,而在比较A[0:4]与B时在A[4]处发生不匹配现象,所以,再拿A[1:5]、A[2:6]、A[3:7]分别与B比较是没有意义的,直接比较A[4:8]与B即可。这样就省掉了几次循环。
KMP算法在分析检索关键词时需要考虑的问题还有很多,这里就不一一分析了,下面是C实现的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getNext( char* keyword, char* next){
    int i = 0, j = -1;
    next[0] = -1;

    int end_pos = strlen(keyword)-1;
    while(i < end_pos){
        if(j == -1 || keyword[j] == keyword[i]){
            ++ i;
            ++ j;
            next[i] = j;
        }
        else{
            j = next[j];
        }
    }
}

int find( char *string, char *keyword){
    int i = 0, j = 0, len = strlen(string), klen = strlen(keyword);
    char *next = (char*)malloc( strlen(keyword));
    getNext(keyword, next);

    while(i < len && j < klen){
        if(j == -1 || string[i] == keyword[j]){
            ++i;
            ++j;
        }
        else{
            j = next[j];
        }
    }
    free(next);
    if(j == klen){
        return i-klen;
    }
    else{
        return -1;
    }
}

int main(){
    char *keyword = "abcdef";
    char next[strlen(keyword)];
    getNext(keyword, next);

    int i;
    int len = strlen(keyword);
    printf("next:" );
    for(i = 0; i != len; ++i){
        printf("%d" , next[i]);
    }
    printf("\n" );

    int pos = find("adadababcdefcf", keyword);

    printf(" pos = %d\n", pos);

    return 0;
}

优化KMP算法
为了更大限度的减少重复匹配次数,还可以对KMP算法进行优化,优化步骤非常简单,下面是优化后的代码,新增的代码后都标有line开头的注释:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getNext( char* keyword, char* next){
    int i = 0, j = -1;
    next[0] = -1;

    int end_pos = strlen(keyword)-1;
    while(i < end_pos){
        if(j == -1 || keyword[j] == keyword[i]){
            ++ i;
            ++ j;
            if(keyword[j] == keyword[i]){            // line 1
                next[i] = next[j];                   // line 2
            }                                        // line 3
            else{                                    // line 4
                next[i] = j;                         // line 5
            }                                        // line 6
        }
        else{
            j = next[j];
        }
    }
}

int find( char *string, char *keyword){
    int i = 0, j = 0, len = strlen(string), klen = strlen(keyword);
    char *next = (char*)malloc( strlen(keyword));
    getNext(keyword, next);

    while(i < len && j < klen){
        if(j == -1 || string[i] == keyword[j]){
            ++i;
            ++j;
        }
        else{
            j = next[j];
        }
    }
    free(next);
    if(j == klen){
        return i-klen;
    }
    else{
        return -1;
    }
}

int main(){
    char *keyword = "ababa";
    char next[strlen(keyword)];
    getNext(keyword, next);

    int i;
    int len = strlen(keyword);
    printf("next:" );
    for(i = 0; i != len; ++i){
        printf("%d" , next[i]);
    }
    printf("\n" );

    int pos = find("abasbabababababababababab", keyword);

    printf("pos = %d\n", pos);

    return 0;
}

其实,理解起来也比较简单,对于检索关键词K:"ababa"这种情况,假设外层循环计数变量为i,如果在K[0]处发生不匹配,则下次循环前i应该自加,重新与K进行比较,而如果在K[1]处发生不匹配时,则下次循环前,i无需自加,直接与K进行比较,但是如果在K[2]处发生不匹配时,则下次循环前,i应该自加然后与K进行匹配,因为K[2]跟K[0]相等,K[2]与之不匹配则K[0]也与之不匹配,所以i需要自加,从后一个元素开始比较。




本文链接: http://blog.csdn.net/girlkoo/article/details/17435557
本文作者:girlkoo
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值