KMP字符串查找

来源:互联网 发布:数据中心的网络交换机 编辑:程序博客网 时间:2024/05/21 07:59
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 0
原创粉丝点击