BM算法
BM算法的一个特点是当不匹配的时候一次性可以跳过不止一个字符。即它不需要被搜索的字符串中的字符进行逐一比较,而会跳过其中的某些部分。通常搜索的关键字越长,算法速度越快。它的效率来源:对每一次失败的匹配尝试,算法都能够使用这些信息来排除尽可能多的无法匹配位置。它充分的利用待搜索字符串的一些特征,加快了搜索的步骤。
基于以下两个规则让模式每次向右移动的尽可能大的距离:
坏字符规则:当文本字符串中的某个字符跟模式串的某个字符不匹配时,我们称文本串中的这个失配字符为坏字符,此时模式串需要向右移动,移动的位数=坏字符在模式串中的位置-坏字符在模式串中的最右出现的位置。如果“坏字符”不包含在模式串之中,则最右出现的位置-1.坏字符针对的是文本串。
好后缀规则:当字符失配时,后位移数=好后缀在模式串中的位置-好后缀在模式串上一次出现的位置,且如果好后缀在模式串中没有再次出现,则为-1.好后缀针对的是模式串。
坏字符出现的时候有两种情况:
1.模式串中没有出现了文本串中的那个坏字符,将模式串直接整体对齐到这个字符的后方,继续比较。
2.模式串中有对应的坏字符时,让模式串中最靠右的对应字符与坏字符相对。(最靠右)
好后缀规则:
1.如果模式串中存在已经匹配成功的好后缀,则把目标串与好后缀对齐,然后从模式串的最尾元素开始往前匹配。
2.如果无法找到匹配好的后缀,找一个匹配的最长的前缀,让目标串与最长的前缀对齐(如果这个前缀存在的话)。模式串【m-s,m】=模式串【0,s】
3.如果完全不存在和好后缀匹配的子串,则右移整个模式串。
贴上代码:
#include<iostream>
#define MAX 200
using namespace std;
void get_dist(int* dist, char* t, const int lenT)
{
int i;
for (i = 0; i <= MAX; i++)
dist[i] = lenT;
for (i = 0; i < lenT; i++)
dist[(int)t[i]] = lenT - i - 1;
}
int BM(char* s, char* t, int* dist, const int lenS, const int lenT)
{
int i, j, k;
i = lenT - 1;
while (i < lenS)
{
j = lenT - 1;
k = i;
while (j >= 0 && s[k] == t[j])
{
j--;
k--;
}
if (j < 0)
return i + 2 - lenT;
else
i = i + dist[s[k]];
}
if (i >= lenS)
return 0;
}
int main()
{
int cases;
char s[MAX], t[MAX];
int dist[MAX];
cout << "请输入案例的个数:";
cin >> cases;
while (cases--)
{
cout << "请输入主串:" << endl;
cin >> s;
int lenS = strlen(s);
while (1)
{
cout << "请输入需要匹配的模式串(以0结束):" << endl;
cin >> t;
if (!strcmp(t, "0"))
break;
int lenT = strlen(t);
get_dist(dist, t, lenT);
int pos = BM(s, t, dist, lenS, lenT);
if (pos == 0)
cout << "没有匹配项!" << endl;
else
cout << "匹配的开始位置为:" << pos << endl;
}
}
system("pause");
return 0;
}
本文参考: