介绍
串的模式匹配,是求一个字符串在另一个字符串中第pos个字符以后的位置:
int Index(SString S,SString T,int pos);
S称为主串,T称为模式串。
目录
1. 简单的模式匹配
2. 首尾模式匹配
3. KMP算法
参考资料
1、严蔚敏《数据结构(C语言版)》
2、王道考研2018年数据结构考研复习指导
3、教学ppt
一、简单的模式匹配
称为朴素算法(BF算法):
从主串S指定的字符开始和模式串T的第pos个字符比较,匹配就继续比较S、T的下一个字符,如果不匹配,从S的下一个字符开始,重新与T的第一个字符比较。如果S中的字符都匹配完了,仍然没有匹配成功(此时T中字符序号小于或等于T的长度)。把S、T的长度分别保存在S[0],T[0]中,算法如下:
int Index(SSrting S,SString T,int pos){
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;
}
该算法的时间复杂度为:O(mn)。m、n分别为T、S的长度。但在一般情况下,朴素的模式匹配算法的实际执行时间近似O(m+n)。
二、首尾模式匹配
核心思思:先比较模式串中的第一个字符,再比较模式串中最后一个字符,如果都相等,比较中间的字符。
代码如下:
int Index(SSrting S,SString T,int pos){
sLength=S[0];tLength=T[0];
i=pos;
patStartChar=T[1];patEndChat=T[tLength];
while(i<=sLength-tLength+1){
if(S[i]!=patStartChar)++i;
else if(s[i+tLength-1]!=patEndChat)++i;
else{
k=1;j=2;
while(j<tLength&&s[i+k]==T[j]){
++k;++j;
}
if(j==tLength)return i;
else ++i;
}
}
return 0;
}
算法的时间复杂度O(mn)。
三、改进的模式匹配算法——KMP算法
这个算法琢磨了好久才明白,核心思想是:每当一趟匹配过程中出现字符比较不相等时,不需回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续比较。
重点在于求next[j]。
next数组的求解就是对每个位置之前的字符的前缀后缀找到最长的公共字符串长度。定义是:
next[j]=
1、0——当j=1时
2、Max{k|1<k<j且’p1……pk-1’=’pj-k+1……pj-1’}——当这个集合不空时
3、1——其他情况
next求解举例:
T:ababaaababaa
tLength=12
j | T | next[j] |
---|---|---|
1 | a | 0 |
2 | a b | 1 |
3 | ab a | 1 |
4 | a b a b | 2 |
5 | ab ab a | 3 |
6 | ababa a | 4 |
7 | a baba a a | 2 |
8 | a babaa a b | 2 |
9 | ab abaa ab a | 3 |
10 | aba baa aba b | 4 |
11 | abab aa abab a | 5 |
12 | ababa a ababa a | 6 |
算法代码:
当匹配过程失败,i不变,j退回到next[j]的位置,重新比较。同时,当j为0时,i与j同时加1。即:若主串S的第i个位置和模式串的第一个字符不等,应从主串的第i+1个位置开始匹配。
int Index_KMP(SSrting S,SString T,int pos){
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;
}
void get_next(SString T,int 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];
}
}
时间复杂度为O(n+m)。
通常,模式串的长度m比主串的长度n要小得多,因此,对整个匹配算法来说,所增加的这点时间是值得的。
KMP最大的特点/优点是主串指针i不回溯,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,无需回头重读。
而由于一般情况下,朴素的模式匹配算法的实际执行时间近似O(m+n),因此至今仍被采用。KMP算法仅仅是在主串与子串有很多“部分匹配”时才显得比朴素的算法快得多。