实现后向不确定Dawg匹配算法

时间:2019-02-13 15:23:16

标签: c++ algorithm

我正在尝试在我的代码中实现BNDM算法,以便执行快速模式搜索。

我找到了一些代码online,并尝试针对自己的用例进行调整:

codeadjusted

我认为在更改值时我做错了,因为该算法需要几分钟才能完成(我期望它更快)。


使用 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;
}

1 个答案:

答案 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,而是将它们初始化为模式中通配符位置的掩码。

我不知道这是否足以使算法与通配符一起使用,但是值得一试。