KMP模式串匹配模板

来源:互联网 发布:sql server 2005 教程 编辑:程序博客网 时间:2024/05/22 06:19

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

BF算法是一种很好理解的字符串匹配算法,但是其时间复杂度为O(mn),在实际应用中无法快速查询到匹配串。

KMP其实是改版的BF,只是,在BF中,一旦失配,被匹配串下标+1,匹配串的下标回溯到0,忽略了已经匹配的部分的作用,

KMP借助next数组,将到当前位置j之前的最大前缀放在next[j]中,如果在j处失配,只需将j挪到next[j]处就可以

next数组比较难理解,但是,多翻几篇博客就理解了。。。(懒得解释,恶心死了。只能意会不可言传,自己画个字符串算算就差不多了)

next数组有两种求法,

第一种:数据结构课本(严蔚敏)版的

void do_next(char *p){//构造next数组;int len = strlen(p);int k = -1;next[0] = -1;int j=0;while(j<len-1){//k==-1,表示到当前的j前无法找到相应的前缀。 if(k==-1||p[k]==p[j]){++k;++j;next[j] = k;}else{//更新当前情况下的最大前缀。 k = next[k];}}} 
第二种,优化后的next数组

void getNext2(){    int i = 0; //pattern串的下标    int j = -1; //    next[0] = -1;    while (i < pattern_len - 1)    {         if (j == -1 || pattern[i] == pattern[j])        {            ++i;            ++j;            if (pattern[i] != pattern[j]) //正常情况                next[i] = j;            else //特殊情况,这里即为优化之处。考虑下AAAAB, 防止4个A形成0123在匹配时多次迭代。                next[i] = next[j];        }        else            j = next[j];    }}

第二种next数组求出的值明显比第一个的小,虽然两个数组值不一样,但是KMP算法的代码是一样的。这个主要难在如何理解next数组的求值方式

希望多查阅博客自行了解,我解释不清楚。。。

给出裸模板

//KMP算法模版#include<stdio.h>#include<string.h>#include<stdlib.h>#define MAX 100int next[MAX];void do_next(char *p){//构造next数组;int len = strlen(p);int k = -1;next[0] = -1;int j=0;while(j<len-1){//k==-1,表示到当前的j前无法找到相应的前缀。 if(k==-1||p[k]==p[j]){++k;++j;next[j] = k;}else{//更新当前情况下的最大前缀。 k = next[k];}}} int KMP(char *T,char *p){int i=0;int j=0;int ans=-1;int lenT = strlen(T);int lenP = strlen(p);while(i<lenT){if(j==-1||T[i]==p[j]){++i;++j;}else{j = next[j];}if(j==lenP){return ans = i-lenP+1;}}return ans;}int main(){char p[5]={'a','b','a','a'};char T[15]={'a','b','c','a','b','a','a','a','a'};do_next(p);for(int i=0;i<4;i++){printf("%d ",next[i]);}putchar('\n');printf("%d\n",KMP(T,p));return 0;}

返回匹配串在被匹配串的下标

0 0
原创粉丝点击