BM字符串匹配算法
http://www.cnblogs.com/dsky/archive/2012/05/04/2483190.html
在用于查找子字符串的算法当中,BM(Boyer-Moore)算法是目前相当有效又容易理解的一种,一般情况下,比KMP算法快3-5倍。
BM算法在移动模式串的时候是从左到右,而进行比较的时候是从右到左的。
BM算法实际上包含两个并行的算法,坏字符算法和好后缀算法。这两种算法的目的就是让模式串每次向右移动尽可能大的距离(j+=x,x尽可能的大)。
几个定义:
例主串和模式串如下:
主串 : mahtavaatalomaisema omalomailuun
模式串: maisemaomaloma
好后缀:模式串中的aloma为“好后缀”。
坏字符:主串中的“t”为坏字符。
好后缀算法
如果程序匹配了一个好后缀, 并且在模式中还有另外一个相同的后缀, 那
把下一个后缀移动到当前后缀位置。好后缀算法有两种情况:
Case1:模式串中有子串和好后缀安全匹配,则将最靠右的那个子串移动到好后缀的位置。继续进行匹配。
Case2:如果不存在和好后缀完全匹配的子串,则在好后缀中找到具有如下特征的最长子串,使得P[m-s…m]=P[0…s]。说不清楚的看图。
坏字符算法
当出现一个坏字符时, BM算法向右移动模式串, 让模式串中最靠右的对应字符与坏字符相对,然后继续匹配。坏字符算法也有两种情况。
Case2:模式串中不存在坏字符。见图。
移动规则
BM算法的移动规则是:
将概述中的++j,换成j+=MAX(shift(好后缀),shift(坏字符)),即
BM算法是每次向右移动模式串的距离是,按照好后缀算法和坏字符算法计算得到的最大值。
shift(好后缀)和shift(坏字符)通过模式串的预处理数组的简单计算得到。好后缀算法的预处理数组是bmGs[],坏字符算法的预处理数组是BmBc[]。
BM算法子串比较失配时,按坏字符算法计算模式串需要向右移动的距离,要借助BmBc数组。
注意BmBc数组的下标是字符,而不是数字。
BmBc数组的定义,分两种情况。
1、 字符在模式串中有出现。如下图,BmBc[‘k’]表示字符k在模式串中最后一次出现的位置,距离模式串串尾的长度。
2、 字符在模式串中没有出现:,如模式串中没有字符p,则BmBc[‘p’] = strlen(模式串)。
BM算法子串比较失配时,按好后缀算法计算模式串需要向右移动的距离,要借助BmGs数组。
BmGs数组的下标是数字,表示字符在模式串中位置。
BmGs数组的定义,分三种情况。
1、 对应好后缀算法case1:如下图:i是好后缀之前的那个位置。
2、 对应好后缀算法case2:如下图所示:
3、 当都不匹配时,BmGs[i] = strlen(模式串)
在计算BmGc数组时,为提高效率,先计算辅助数组Suff。
Suff数组的定义:suff[i] = 以i为边界, 与模式串后缀匹配的最大长度,即P[i-s...i]=P[m-s…m]如下图:
举例如下:
分析
用Suff[]计算BmGs的方法。
1) BmGs[0…m-1] = m;(第三种情况)
2) 计算第二种情况下的BmGs[]值:
for(i=0;i
if(-1==i || Suff[i] == i+1)
for(;j < m-1-i;++j)
if(suff[j] == m)
BmGs[j] = m-1-i;
3) 计算第三种情况下BmGs[]值,可以覆盖前两种情况下的BmGs[]值:
for(i=0;i
BmGs[m-1-suff[i]] = m-1-i;
如下图所示:
Suff[]数组的计算方法。
常规的方法:如下,很裸很暴力。
Suff[m-1]=m;
for(i=m-2;i>=0;--i){
q=i;
while(q>=0&&P[q]==P[m-1-i+q])
--q;
Suff[i]=i-q;
}
有聪明人想出一种方法,对常规方法进行改进。基本的扫描都是从右向左。改进的地方就是利用了已经计算得到的suff[]值,计算现在正在计算的suff[]值。
如下图所示:
i是当前正准备计算的suff[]值得那个位置。
f是上一个成功进行匹配的起始位置(不是每个位置都能进行成功匹配的, 实际上能够进行成功匹配的位置并不多)。
q是上一次进行成功匹配的失配位置。
如果i在q和f之间,那么一定有P[i]=P[m-1-f+i];并且如果suff[m-1-f+i]=i-q, suff[i]和suff[m-1-f+i]就没有直接关系了。
1 int BMMatch(byte* pSrc, int nSrcSize, byte* pSubSrc, int nSubSrcSize)
2 {
3
4 //1.坏字符数组
5 int bcSkip[256];
6 for( int i = 0; i < 256; i++)
7 {
8 bcSkip[i] = nSubSrcSize;
9 }
10 for (int i = 0; i < nSubSrcSize - 1; i++)
11 {
12 bcSkip[pSubSrc[i]] = nSubSrcSize - i - 1;
13 }
14
15 //2.好后缀数组
16 int* suffix = new int [nSubSrcSize];
17 suffix[nSubSrcSize - 1] = nSubSrcSize;
18 for (int i = nSubSrcSize - 2; i >= 0; i--)
19 {
20
21 int k = i;
22 while( k >= 0 && pSubSrc[k] == pSubSrc[nSubSrcSize-1-i+k] )
23 {
24 k--;
25 }
26 suffix[i] = i - k;
27 }
28
29 int* gsSkip = new int [nSubSrcSize];
30 for (int i = 0; i < nSubSrcSize; i++)
31 {
32 gsSkip[i] = nSubSrcSize;
33 }
34 for (int i = nSubSrcSize - 1; i >= 0; i--)
35 {
36 if (suffix[i] == i + 1)
37 {
38 for (int j = 0; j < nSubSrcSize - 1 - i; ++j)
39 {
40 if (gsSkip[j] == nSubSrcSize)
41 gsSkip[j] = nSubSrcSize - 1 - i;
42 }
43 }
44 }
45 for (int i = 0; i <= nSubSrcSize - 2; ++i)
46 {
47 gsSkip[nSubSrcSize - 1 - suffix[i]] = nSubSrcSize - 1 - i;
48 }
49
50 int nPos = 0;
51 while (nPos <= nSrcSize - nSubSrcSize)
52 {
53 int j = nSubSrcSize - 1;
54 while(j >= 0 && pSubSrc[j] == pSrc[j + nPos])
55 {
56 j--;
57 }
58 if (j < 0)
59 break;
60 else
61 {
62 nPos += max(gsSkip[j], bcSkip[pSrc[j + nPos]]-(nSubSrcSize - 1 - j) );
63 }
64 }
65 delete[] gsSkip;
66 return (nPos > nSrcSize - nSubSrcSize)? -1 : nPos;
67 }
1 int BMMatchEx(byte* pSrc, int nSrcSize, byte* pSubSrc, int nSubSrcSize)
2 {
3
4 //1.坏字符数组
5 int bcSkip[256];
6 for( int i = 0; i < 256; i++)
7 {
8 bcSkip[i] = nSubSrcSize;
9 }
10 for (int i = 0; i < nSubSrcSize - 1; i++)
11 {
12 bcSkip[pSubSrc[i]] = nSubSrcSize - i - 1;
13 }
14
15 //2.好后缀数组
16 int* suffix = new int [nSubSrcSize];
17 suffix[nSubSrcSize - 1] = nSubSrcSize;
18 int g = nSubSrcSize - 1;
19 int f = 0;
20 for (int i = nSubSrcSize - 2; i >= 0; i--)
21 {
22 if(i > g && suffix[i + nSubSrcSize - 1 - f] < i - g)
23 {
24 suffix[i] = suffix[i + nSubSrcSize - 1 - f];
25 }
26 else
27 {
28 if (i < g)
29 {
30 g = i;
31 }
32 f = i;
33 while( g >= 0 && pSubSrc[g] == pSubSrc[nSubSrcSize-1-f+g] )
34 {
35 g--;
36 }
37 suffix[i] = f - g;
38 }
39 }
40
41 int* gsSkip = new int [nSubSrcSize];
42 for (int i = 0; i < nSubSrcSize; i++)
43 {
44 gsSkip[i] = nSubSrcSize;
45 }
46 for (int i = nSubSrcSize - 1; i >= 0; i--)
47 {
48 if (suffix[i] == i + 1)
49 {
50 for (int j = 0; j < nSubSrcSize - 1 - i; ++j)
51 {
52 if (gsSkip[j] == nSubSrcSize)
53 gsSkip[j] = nSubSrcSize - 1 - i;
54 }
55 }
56 }
57 for (int i = 0; i <= nSubSrcSize - 2; ++i)
58 {
59 gsSkip[nSubSrcSize - 1 - suffix[i]] = nSubSrcSize - 1 - i;
60 }
61
62 int nPos = 0;
63 while (nPos <= nSrcSize - nSubSrcSize)
64 {
65 int j = nSubSrcSize - 1;
66 while(j >= 0 && pSubSrc[j] == pSrc[j + nPos])
67 {
68 j--;
69 }
70 if (j < 0)
71 break;
72 else
73 {
74 nPos += max(gsSkip[j], bcSkip[pSrc[j + nPos]]-(nSubSrcSize - 1 - j) );
75 }
76 }
77 delete[] gsSkip;
78 return (nPos > nSrcSize - nSubSrcSize)? -1 : nPos;
79 }