我正在尝试在我的代码中实现BNDM算法,以便执行快速模式搜索。
我找到了一些代码online,并尝试针对自己的用例进行调整:
我认为在更改值时我做错了,因为该算法需要几分钟才能完成(我期望它更快)。
使用 std :: search 需要30秒(带通配符)。 这大约需要4-5分钟(不带通配符)。
我将所有内容强制转换为(无符号字符)的原因是因为程序崩溃,否则,因为我的数据和模式都包含十六进制值。
我想知道的是,此实现在哪里出错(为什么运行这么慢)?以及如何包含搜索包含通配符的模式的功能?
编辑* 通过将构建从调试切换到发布,已解决了速度问题。 另外,将B数组的大小更改为256可以使其更快。
我目前唯一的问题是如何使用此算法实现使用通配符的方法。
当前代码:
vector<unsigned int> get_matches(const vector<char> & data, const string & pattern) {
vector<unsigned int> matches;
//vector<char>::const_iterator walk = data.begin();
std::array<std::uint32_t, 256> B{ 0 };
int m = pattern.size();
int n = data.size();
int i, j, s, d, last;
//if (m > WORD_SIZE)
// error("BNDM");
// Pre processing
//memset(B, 0, ASIZE * sizeof(int));
s = 1;
for (i = m - 1; i >= 0; i--) {
B[(unsigned char)pattern[i]] |= s;
s <<= 1;
}
// Searching phase
j = 0;
while (j <= n - m) {
i = m - 1; last = m;
d = ~0;
while (i >= 0 && d != 0) {
d &= B[(unsigned char)data[j + i]];
i--;
if (d != 0) {
if (i >= 0)
last = i + 1;
else
matches.emplace_back(j);
}
d <<= 1;
}
j += last;
}
return matches;
}
答案 0 :(得分:2)
B
不够大-它由模式中的字节索引,因此它必须具有256个元素(假设是8位字节体系结构。)但是您将其定义为具有pattern.size()
元素,数量要少得多。
因此,您正在使用B分配之外的内存,这是未定义的行为。
我建议您使用std::array<std::uint32_t, 256>
,因为您无需调整B
的大小。 (甚至更好,std::array<std::uint32_t, std::numeric_limits<unsigned char>::max()+1>
)。
我不是该特定搜索算法的专家,但是如果字符p
匹配,则预处理步骤似乎设置为c
的元素B
中的位c
模式元素p
。由于通配符模式元素可以匹配任何字符,因此B
的每个元素都应具有与通配符字符集相对应的位,这似乎是合理的。换句话说,不是将B
的每个元素都初始化为0,而是将它们初始化为模式中通配符位置的掩码。
我不知道这是否足以使算法与通配符一起使用,但是值得一试。