BM算法总结
- 格式:doc
- 大小:49.00 KB
- 文档页数:3
BM算法(全称Boyer-Moore Algorithm)是一种精确字符串匹配算法(只是一个启发式的字符串搜索算法)。BM算法不同于KMP算法,采用从右向左比较的方法,同时引入了两种启发式Jump规则,即Bad-Character和Good-Suffix,来决定模板向右移动的步长。
BM算法的基本流程:
文本串T(待匹配的字符串,长度n),模式串为P(用于去匹配的字符串模板,长度设为m)。首先将T与P进行左对齐,然后进行从右向左比较(此时不移动模板和文本的相对位置,仅仅比较对齐位置上面是否相同,方向是右向左)。若是某趟比较不匹配时,BM算法就采用两条启发式规则,即前面提到的Bad-Character和Good-Suffix,来计算模式串P向右移动的步长,直到整个匹配过程的结束。
1)Bad-character
BM 算法在上图中从右向左匹配中第一个字符就出现不一致的情况,此时需要采
用两种情况来处理:
a) 如果T 中不匹配字符E 在模式P 中没有出现,那么我们很容易就能理解为E
开始的m 长度的字符串不可能匹配到P(直观,无需解释),我们可以直接
把P 跳过E,匹配后面的内容。
b) 如果E 在模式P 中未进行匹配的字段中出现了,则以该字符E 进行对齐。
BM算法实现
2)Good Suffix
若发现某个字符不匹配的同时,已有部分字符匹配成功,则按如下两种情况进行:
a) 如果在P中位置t处已经匹配部分P’在P中某位置t’也出现,且位置t’的前一个字符与位置t的前一个字符不相同,则将P右移使t’对应t所在的位置。
b) 如果P中任何位置已经匹配部分P’没有再出现,则找到与P’的后缀P’’相同的P的最长前缀x,向右移动P,使x对应刚才P’’后缀所在位置
下面两个链接解释的很好:
/sealyao/archive/2009/09/18/4568167.aspx
http://www-igm.univ-mlv.fr/~lecroq/string/node14.html#SECTION00140
void preBmBc(char *x, int m, int bmBc[]) //坏字符表预处理,x就是上文中的模式串P
{
int i; //注意:bmBc数组的下标是字符,而不是数字
for (i = 0; i < ASIZE; ++i) //初始将所有ASIZE=256个字符都赋初值为模式串的长度m,
bmBc[i] = m; //也就是说模式串中没出现的字符,相应的移动距离都为m
for (i = 0; i < m - 1; ++i)
bmBc[x[i]] = m - i - 1;
}
Suffixes[]数组的计算方法。常规的方法如下:很裸很暴力。这种方法比下面那种容易理解。
void suffixes(char *P, int m, int *suff){
Suff[m-1]=m;
for(i=m-2;i>=0;--i)
{g=i;
while(g>=0&&P[g]==P[m-1-i+g])
--g;
Suff[i]=i-g;
}
} Suffixes[]数组计算方法二
void suffixes(char *x, int m, int *suff) //最长后缀匹配数组预处理
{
int f, g, i;
suff[m - 1] = m;
g = m - 1;
for (i = m - 2; i >= 0; --i) {
if (i > g && suff[i + m - 1 - f] < i - g)
suff[i] = suff[i + m - 1 - f];
else {
if (i < g)
g = i;
f = i;
while (g >= 0 && x[g] == x[g + m - 1 - f])
--g;
suff[i] = f - g;
}
}
}
例:
bmBc and bmGs tables used by Boyer-Moore algorithm
void preBmGs(char *x, int m, int bmGs[]) //好后缀数组预处理
{ int i, j, suff[XSIZE];
suffixes(x, m, suff);
for (i = 0; i < m; ++i)
bmGs[i] = m;
j = 0;
for (i = m - 1; i >= 0; --i)
if (suff[i] == i + 1)
for (; j < m - 1 - i; ++j)
if (bmGs[j] == m)
bmGs[j] = m - 1 - i;
图1
for (i = 0; i <= m - 2; ++i)
bmGs[m - 1 - suff[i]] = m - 1 - i;
}
图2
void BM(char *x, int m, char *y, int n) {
int i, j, bmGs[XSIZE], bmBc[ASIZE];//XSIZE为模式串的长度,ASIZE为字母表的长度256
/* Preprocessing */
preBmGs(x, m, bmGs);
preBmBc(x, m, bmBc);
/* Searching */
j = 0;
while (j <= n - m) {
for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i);
if (i < 0) {
OUTPUT(j);
j += bmGs[0];//匹配到一个相同的串后,向后移动m位,
//继续匹配文本串后续的串
}
else
j += MAX(bmGs[i], bmBc[y[i + j]] - m + 1 + i);
}
}