BM算法详解

    1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法:Boyer-Moore算法,简称BM算法。该算法从模式串的尾部开始匹配,且拥有在最坏情况下O(N)的时间复杂度。一般情况下,比KMP算法快3-5倍。BM算法在移动模式串的时候是从左到右,而进行比较的时候是从右到左的。常规的匹配算法移动模式串的时候是从左到右,而进行比较的时候也是是从左到右的。

BM算法思想:

        BM算法实际上包含两个并行的算法,坏字符算法和好后缀算法。这两种算法的目的就是让模式串每次向右移动尽可能大的距离。

BM算法定义了两个规则:

       坏字符规则:当文本串中的某个字符跟模式串的某个字符不匹配时,我们称文本串中的这个失配字符为坏字符,此时模式串需要向右移动,移动的位数 = 坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置。此外,如果"坏字符"不包含在模式串之中,移动的长度为模式串的长度。

BM算法详解_第1张图片

移动后

BM算法详解_第2张图片

      好后缀规则:当字符失配时,按好后缀算法计算模式串需要向右移动的距离,要借助BmGs数组

BmGs数组的定义,分三种情况。

      为了实现好后缀规则,需要定义一个数组suffix[],其中suffix[i] = s 表示以i为边界,与模式串后缀匹配的最大长度,如下图所示,用公式可以描述:满足P[i-s, i] == P[m-s, m]的最大长度s。

1、模式串中没有子串匹配上后后缀,并且在模式串中找不到最长前缀,让该前缀等于好后缀的后缀。此时,直接移动模式到好后缀的下一个字符

BM算法详解_第3张图片
2、 对应好后缀算法:如下图:模式串中有子串匹配上好后缀。

BM算法详解_第4张图片


3、模式串中没有子串匹配上后后缀,此时需要寻找模式串的一个最长前缀,并让该前缀等于好后缀的后缀,寻找到该前缀后,让该前缀和好后缀对齐即可。

BM算法详解_第5张图片

注意这种情况:

模式串:bcbcgfdabcbc
              suff[3]=4 suff[1]=2
              bmGs[0...7]=8;
              bmGs[8...9]=10;//与最右边的进行比配,所以要移动距离小 


#include
#include
#include
#define SIZE 26 
using namespace std;

int max(int a,int b)
{
	return a>b?a:b;
}

//1、 字符在模式串中有出现。如下图,BmBc[‘k’]表示字符k在模式串中最后一次出现的位置,距离模式串串尾的长度。
//2、 字符在模式串中没有出现:,如模式串中没有字符p,则BmBc[‘p’] = strlen(模式串)。
char* Bad_Char(char *P)   // 数组bmBc['k'],表示坏字符‘k’在模式串中出现的位置距离模式串末尾的最大长度
{
	int m = strlen(P);
	char *bmBc = new char[SIZE];	
	int i;
	for(i=0;i=0;i--)
	{
		int q=i;
		while(q>=0&&P[q]==P[m-1-i+q])
		q--;
		suff[i]=i-q;
	}
	return suff;
}

//如果程序匹配了一个好后缀, 并且在模式中还有另外一个相同的后缀, 那
//把下一个后缀移动到当前后缀位置

//case1:模式串中没有子串匹配上后后缀,并且在模式串中找不到最长前缀,让该前缀等于好后缀的后缀。此时,直接移动模式到好后缀的下一个字符
//Case2:模式串中有子串和好后缀安全匹配,则将最靠右的那个子串移动到好后缀的位置。继续进行匹配。
//Case3:如果不存在和好后缀完全匹配的子串,则在好后缀中找到具有如下特征的最长子串,使得P[m-s…m]=P[0…s]。说不清楚的看图
 
char *Good_Str(char *P)
{
	int m=strlen(P);
	char *suff = suffix(P);
	char *bmGs = new char[m];
	memset(bmGs,m,sizeof(char)*m);  //case 1: 
	
	
	int j=0;
	for(int i=m-1;i>=0;i--)  //case 3: 选择右移最小的 
	{
		if(suff[i]==i+1)
		 for (; j < m - 1 - i; ++j) 	 
		 if (bmGs[j] == m)  
		 bmGs[j] = m - 1 - i;  //当i>k时,suff[i]=i+1 &&suff[k]=k+1 取  j=0&&P[i]==T[i+j];i--); 
		if(i<0)
		{
		printf("%d",j);
		j+=bmGs[0];
		}
		else
		j+=max(bmGs[i],bmBc[T[i+j]-'a']-(m-1-i));
	}
}

int main(){
	char T[]="adcdgabcdjhabcabcdaderdfgfdg"; 
	char P[]="gabcdj";
	char *p1=Bad_Char(P);

	for(int i=0;i

        考虑模式串匹配不上母串的最坏情况,KM算法的时间复杂度最坏是O(n×m),最好是O(n),其中n为母串的长度,m为模式串的长度。




你可能感兴趣的:(Algorithm)