字符串模式匹配
1.BF算法
初始时让目标T的第 0 位与模式P的第 0 位对齐;
顺序比对目标T与模式P中的对应字符:
若 P 与 T 比对发现对应位不匹配,则本趟失配。将 P 右移一位与 T 对齐,进行下一趟比对;
若 P 与 T 对应位都相等,则匹配成功,返回 T当前比较指针停留位置减去 P 的长度,即目标T 中匹配成功的位置,算法结束。
若 P 与 T 比对过程中,T 后面所剩字符个数少于 P 的长度,则模式匹配失败。
时间复杂度为O(m*n)
int Find(Hstring &T,Hstring &p)
{
int i,j,k;
for(i=0;i<=T.n-P.n;i++)
{
for(k=i,j=0;j<P.n;j++,k++)
{
if(T.ch[k]!=P.ch[j])
break;
}
if(j==P.n)
return i;
}
return -1;
}
若设 n 为目标 T 的长度,m 为模式 P 的长度,匹配算法最多比较 n-m+1趟。若每趟比较都比较到模式 P 尾部才出现不等,要做 m 次比较,则在最坏情况下,总比较次数 (n-m+1)m。在多数场合下 m 远小于 n,因此,算法的运行时间为O(nm)。
BF算法低效的原因在于每趟重新比较时,目标 T 的检测指针要回退。
如果消除了每趟失配后为实施下一趟比较时目标指针的回退,可以提高模式匹配效率。
2.无回溯的KMP算法
KMP是指D.E.Knuth、J.H.Morris和V.R.Pratt。
实施KMP算法,若一趟匹配过程比对失配,在做下一趟匹配比对时,目标 T 的检测指针不回退,模式 P 右移,与 T 的检测指针对齐 再开始比对过程,算法的时间代价:
若每趟第一个不匹配,比较n-m+1趟,总比较次数最坏达(n-m)+m = n。
若每趟第 m 个不匹配,总比较次数最坏亦达到 n。
目标 T t0 t1 t2 …… tm-1 … tn-1
模式 P p0 p1 p2 …… pm-1 若失配,右移
目标 T t0 t1 t2 …… tm-1 tm … tn-1
模式 P p0 p1 …… pm-2 pm-1 若失配,右移
目标 T t0 t1 …… ti ti+1…… ti+m-2 ti+m-1… tn-1
模式 P p0 p1 …… pm-2 pm-1
T t0 t1 … ts-1 ts ts+1 ts+2 … ts+j-1 ts+j ts+j+1 … tn-1
‖ ‖ ‖ ‖ ‖ !=
P p0 p1 p2 … pj-1 pj
则有 ts ts+1 ts+2 … ts+j-1 = p0 p1 p2 …pj-1 (1)
为使模式 P 与目标 T 匹配,必须满足
p0 p1 p2 …pj-1 …pm-1 = ts+1 ts+2 ts+3 … ts+j … ts+m
如果 p0 p1 … pj-2 != p1 p2 …pj-1 (2)
则立刻可以断定
p0 p1 …pj-2 !=ts+1 ts+2 … ts+j-1
下一趟必不匹配
同样,若 p0 p1 …pj-3 p2 p3 …pj-1
则再下一趟也不匹配,因为有
p0 p1 …pj-3 ts+2 ts+3 … ts+j-1
直到对于某一个“k”值,使得
p0 p1 …pk+1 != pj-k-2 pj-k-1 …pj-1
且 p0 p1 …pk = pj-k-1 pj-k …pj-1
则 p0 p1 …pk = ts+j-k-1 ts+j-k … ts+j-1
‖ ‖ ‖
pj-k-1 pj-k … pj-1
下一趟可以直接用 pk+1 与 ts+j 继续比较。
最长前缀:
a 0
ab 0
aba 1
abaa 1
abaab 2
abaabc 0
abaabca 1
abaabcac 0
next[j]=[-1,0,0,1,1,2,0,1]
代码如下:
void getNext ( HString& P, int next[] ) {
int j = 0, k = -1;
next[0] = -1; //初始值
while ( j < P.n ) {//计算next[j]
while ( k >= 0 && P.ch[j] != P.ch[k] )
k = next[k]; //缩小前缀、后缀子串长度
j++; k++;
next[j] = k;
}
};
int fastFind ( HString& T, HString& P, int next[ ] ) {
int j = 0, i = 0; //P与T的扫描指针
while ( j < P.n && i < T.n ) { //对两串扫描
if ( j == -1 || P.ch[j] == T.ch[i] ) { j++; i++; } //对应字符匹配,比对位置加一
else j = next[j]; //第 j 位失配,找下一对齐位置
}