KMP匹配算法是当模式串在字符串发生匹配时,而不用在字符串回溯一种模式匹配查询方法。
假设pat=’a b c a b c a c a b’,如果有si=a且si+1!=b,那么进行si+1与a的比较,如果sisi+1=ab且si+2!=c,则出现如下情况:
s=’a b ? ? ?…..?’,符号”?”表示不知道s中此处字符是什么,在s中第一个”?”代表si+2且Si+2!=c, 因此,索搜的下一步应该是对pat的首字符和si+2比较,而无须比较pat的首字符和si+1,因为已经知道si+1与pat的第二个字符相同为b,即si+1!=a,依次类推,假设出现了pat前四个字母的匹配,然后失配,即si+4!=b,则出现一下情况:
s=’a b c a ? ? …..?’
pat=’a b c a a b……b’
因此有以下结果:
定义:令p=p0p1……pn-1是一个模式,则其失配函数f定义为:
例如,对于模式pat=abcabcacab,有:
j: 0 1 2 3 4 5 6 7 8 9
pat: a b c a b c a c a b
f: -1 -1 -1 0 1 2 3 -1 0 1
匹配规则:如果出现了形如si-j….. si-1= p0p1….pj-1且si=pi的部分匹配,那么,若j!=0,则下一趟模式匹配时,从失配字符si和模式串字符pf(j-i)+1处重新开始比较,而若j=0时,则继续比较si+1和p0.注意:f1(j)=f(j),fm(j)=f(fm-1(j)).
KMP算法的关键就是要计算出模式串的失配时其位置可以对应模式串重新匹配的位置,其表达式为:
核心代码:
#include <iostream>
#include<stdio.h>
#include<string.h>
//字符串和模式串的最大长度
#define max_string_size 100
#define max_pattern_size 100
//计算模式串的匹配位置
void fail();
//保存模式串对应位置的匹配信息
int failure[max_pattern_size];
char string[max_string_size];
char pat[max_pattern_size];
using namespace std;
//模式匹配函数
int pmatch();
void fail(char *pat)
{
int n=strlen(pat);
failure[0]=-1;
for(int j=1;j<n;j++)
{
int i=failure[j-1];
//查找j位置字母前一个匹配位置
while((pat[j]!=pat[i+1])&&i>=0)
i=failure[i];
//若当前位置等于查找的位置后一个字母
//则当前配置匹配为i+1,否则就没有匹配的位置
if(pat[j]==pat[i+1])
{
failure[j]=i+1;
}
else
failure[j]=-1;
}
}
int pmatch(char *string, char *pat)
{
int i=0,j=0;
int lens=strlen(string);
int lenp=strlen(pat);
while(i<lens&&j<lenp)
{
//若匹配则匹配下一个
if(string[i]==pat[j])
{
i++;
j++;
}
//没有模式匹配时,则匹配字符串下一个
else if(j==0)
{
i++;
}
//查找模式对应位置的匹配位置
else
{
j=failure[j-1]+1;
}
}
}
经过分析可知道该KMP算法在处理模式匹配的算法时间复杂度是O(strlen(string)+strlen(pat)),而常规的匹配时间复杂度是O(strlen(string)*strlen(pat)).