KMP算法(克努特-莫里斯-普拉特操作)简介

来源:互联网 发布:时代超群步进软件 编辑:程序博客网 时间:2024/04/27 23:12

一,串的模式匹配算法

子串的定位操作通常称作串的模式匹配(其中T称为模式串),是各种串处理系统中最重要的操作之一。求子串位置的定位函数Index(S,T,pos)如下:

int Index(SString S,SString T,int pos){//返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0//其中T非空,1<=pos<=Strlen(S)i = pos; j = 1;while(i <= S[0] && j <= T[0]){if(S[i] == T[j]){i++;j++;}//一个字符匹配成功继续匹配后续字符else{i = i-j+2;j = 1;}//主串指针后退到出发位置的下一位重新匹配}if(j > T[0]) return i - T[0];else return 0;}

算法的基本思想是:从主串S的第pos个字符起和模式串T的第一个字符比较,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式串比较。以此类推直到模式串的每个字符以此和主串中的一个连续的字符序列相等,则称匹配成功,函数值为和模式串T中第一个字符相等的字符在主串S中的序号,否则称匹配不成功,函数值为0。这种算法的时间复杂度为O(m*n)。

二,KMP算法的基本思路

假设主串为's[1]s[2]s[3]...s[n]',模式串为'p[1]p[2]p[3]...p[m]',当主串的第i个字符与模式串中的第j个字符不相同时,并不用将主串指针回溯,而是可以“移动”模式串,使s[i]与j[k]继续比较。那么这个k就应该满足下面的关系:

k是使得  'p[1]p[2]...p[k-1] '  =  's[i-k+1]s[i-k+2]...s[i-1]'  的最大值

记next[j] = k,如果我们已知匹配串每一位的next[j],则KMP算法的子串定位函数为:

int Index_KMP(SString S,SString T,int pos){//利用模式串T的next值求T在主串S的第pos个字符之后的位置//KMP算法i = pos;j = 1;while(i <= S[0] && j <= T[0]){if(j == 0 || S[i] == T[j]){i++;j++;}else j = next[j];}if(j > T[0]) return i - T[0];else return 0;}

三,next[j]的计算方法

当产生“失配”时,已有的部分匹配结果是:

‘p[j-k+1]p[j-k+2]...p[j-1]'  =  's[i-k+1]s[i-k+2]...s[i-1]'

则有:

'p[1]p[2]...p[k-1] '  =  ‘p[j-k+1]p[j-k+2]...p[j-1]'

首先,由定义知,next[1] = 0,

其次,对于任意的j >= 0,

(1)若p[j] == p[next[j]],即:'p[1]p[2]...p[k] '  =  ‘p[j-k+1]p[j-k+2]...p[j]'

则有next[j+1] = next[j] + 1.

(2)若p[j] != p[next[j]],则可将问题看做用模式串匹配模式串自己的问题,那么此时应用p[j]与p[next[next[j]]]比较直到next值为0:

void get_next(SString T,int next[]){     //求模式串T的next函数值并保存在数组next中     i = 1;next[1] = 0;j = 0;     while(i < T[0]){          if(j == 0 || T[i] == T[j]){i++;j++;next[i] = j;}     else j = next[j];     }}//get_next

四,next[j]计算方法的修正

我们发现如果模式串中有类似“aaabaaaaaaab”的结构,那么在计算next值的时候会有很多不必要的重复计算,主要原因就是连续有几个相同的字符,那么其实这些字符的next值是一样的,没有必要反复计算,所以我们需要对计算next的方法进行一些修正:

void get_next(SString T,int next[]){     //求模式串T的next函数值并保存在数组next中     i = 1;next[1] = 0;j = 0;     while(i < T[0]){          if(j == 0 || T[i] == T[j]){       i++;j++;       if(T[i] != T[j]) next[i] = j;  else next[i] = next[j];     }     else j = next[j];     }}//get_next


原创粉丝点击