字符串模式匹配

本文详细介绍了两种字符串模式匹配算法:BF(Brute Force)算法和KMP(Knuth-Morris-Pratt)算法。BF算法效率较低,因每次失配后需回退目标指针;而KMP算法通过预处理避免了回溯,提高了效率。KMP算法利用最长前缀匹配表减少无效比较,降低了时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串模式匹配

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 位失配,找下一对齐位置
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值