【字符串】字符串的模式匹配-BF和KMP

字符串的模式匹配

定义 在字符串中寻找子串(第一个字符)在串中的位置

相关 在串的模式匹配中,子串称为模式,主串称为目标

BF算法

运行时间为O(n*m)

1、初始时让目标T的第 0 位与模式P的第 0 位对齐;
2、顺序比对目标T与模式P中的对应字符:
(1)若 P 与 T 比对发现对应位不匹配,则本趟失配。将 P 右移一位与 T 对齐,进行下一趟比对;
(2)若 P 与 T 对应位都相等,则匹配成功,返回 T当前比较指针停留位置减去 P 的长度,即目标T 中匹配成功的位置,算法结束。
(3)若 P 与 T 比对过程中,T 后面所剩字符个数少于 P 的长度,则模式匹配失败。

模板

int Find(HStirng&T,HString&P)
{
    int i, j, k;	        //T.n-P.n为在T中最后可比对位置
    for ( i = 0; i <= T.n – P.n; i++) //逐趟比对
    {	
        for ( k = i, j = 0; j < P.n; k++, j++ )
            if ( T.ch[k] != P.ch[j] ) break;	//比对不等
        if ( j == P.n ) return i;		//匹配成功
    }
    return -1;				//匹配失败
}

低效的原因在于每趟重新比较时,目标 T 的检测指针要回退。

KMP 算法

若一趟匹配过程比对失配,在做下一趟匹配比对时,目标 T 的检测指针不回退,模式 P 右移(k),与 T 的检测指针对齐,再开始比对过程

字符的比较次数最多为 O(n),n 是目标 T 的长度。

图示如下:
在这里插入图片描述
在这里插入图片描述

模式右移K的确定方法

对于不同的 j(P 中的失配位置),k 的取值不同,它仅依赖于模式 P 本身前 j 个字符的构成,与目标无关。k值实际是j位前的子串的最大重复子串的长度。

可以用一个 next [ ] 失配函数来保存:当模式 P 中第 j 个字符与目标 T 中相应字符失配时,模式 P 中应当由哪个字符(设为第k+1个)与目标中刚失配的字符重新继续进行比较。next[j] = k

next 失配函数的计算

Next 失配函数从0, 1, 2, …, m-1逐项递推计算:
1、当 j = 0时,n0 = -1。设 j > 0 时 nj-1 = k:
2、当 k = -1或 j > 0且 pj-1 = pk,则 nj = k+1。
3、当 pj-1 ≠ pk 且 k ≠ -1,令 k = nk,并让3循环直到条件不满足。
4、当 pj-1 ≠pk 且 k = -1,则 nj = 0。

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;
     }
}; 

模板

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[ ] ) 
{
//在目标 T 中寻找模式 P 的匹配位置。若找到,则函
//数返回 P 在 T 中开始字符下标,否则函数返回-1。
//数组next存放 P 的失配函数next[j]值
    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 位失配,找下一对齐位置
	}
 	if ( j < P.n ) 
 		return -1; //j 未比完失配,匹配失败
	else 
		return i-P.n;	 //匹配成功
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值