Boyer Moore子字符串搜索算法是非常难的算法,但是它的简易版本却是不难的,而且搜索速度很快,下面就学习一下简易版吧。
Boyer Moore是从子串的右到左搜索的,当然搜索主串文本的顺序还是从左到右的。虽然是简化版,但是速度也不比KMP差。
如下图:
如图比较到N的时候与E不匹配,那么我们就在子串里面NEEDLE看看有没有N这个字母,刚好是有的,所有就移到子串N的位置进行比较,那么一下子就跃进了很多了; 在看到了S的位置,不匹配,看看子串里面有没有S这个字母,没有,所以我们整个子串都右移,如此反复最后就找到匹配的了。只比较了4次失败的,加上最后一次成功的6个字母比较,才比较了10次。速度很快。
下面看看它和暴力法的对比程序:
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
class BoyerMoore
{
public:
BoyerMoore(string pat);
int search(string text);
private:
vector<int> rightSkip;
string pat;
};
BoyerMoore::BoyerMoore(string pa):pat(pa)
{
rightSkip.resize(256, -1);
int j = 0;
for (auto s:pat)
rightSkip[s] = j++;
}
int BoyerMoore::search(string text)
{
int n = text.length();
int m = pat.length();
int skip = 0;
//i定位开始比较位置,从i+m-1位置开始向前比较,每次不相等,i向前跃,j复位为m-1
for (int i = 0; i <= n-m; i+=skip)
{
skip = 0;
for (int j = m-1; j >= 0; j--)
{
if (pat[j] != text[i+j])
{
skip = j - rightSkip[text[i+j]];
if(skip < 1) skip = 1;
break;
}
}
if(skip == 0) return i;
}
return n;
}
vector<int> bfSearch(string &text, string &substr)
{
vector<int> begIndex;
int n = text.size();
int m = substr.size();
//注意这里是i<=n-m不是i<n-m
for (int i = 0; i <= n - m; i++)
{
int j = 0;
for (; j < m; j++)
{
if (substr[j] != text[i+j])
{
break;
}
}
if (j == m)
{
//注意这里是i,不是i-m
begIndex.push_back(i);
}
}
return begIndex;
}
int main()
{
string substr1 = "abcadabcab";
BoyerMoore bm(substr1);
string str1 = "abcababcadcabcdceabcadabcabcadabcab";
cout<<bm.search(str1)<<endl;
vector<int> vibf = bfSearch(str1,substr1);
for (int i = 0; i < vibf.size(); i++)
{
cout<<vibf[i]<<" ";
}
cout<<endl;
system("pause");
return 0;
}
记录了出现子串的下标,初次出现的结果是一样的。暴力法记录了全部出现的初次下标。