给出具有整数值的二维数组(数组可以大于10k * 10k ),在数组中搜索给定数字序列的更快方法是什么?
假定文件中的2d数组被读入一个1d大向量中,并以big_matrix(row * x + width)的形式访问。 我想在同一2D数组上进行3种搜索。它们是搜索排序,无序搜索,最佳匹配。这是我使用每种搜索功能的方法。
搜索顺序:此函数查找存在给定数字序列(数字顺序很重要)的所有行。这是找到我实现的给定数字序列的KMP方法:
void searchPattern(std::vector<int> const &pattern, std::vector<int> const &big_matrix, int begin, int finish,
int width, std::vector<int> &searchResult) {
auto M = (int) pattern.size();
auto N = width; // size of one row
while (begin < finish) {
int i = 0;
int j = 0;
while (i < N) {
if (pattern[j] == big_matrix[(begin * width) + i]) {
j++;
i++;
}
if (j == M) {
searchResult[begin] = begin;
begin++;
break;
} else if (i < N && pattern[j] != big_matrix[(begin * width) + i]) {
if (j != 0)
j = lps[j - 1]; // lookup table as in KMP
else
i = i + 1;
}
}
if (j != M) {
searchResult[begin] = -1;
begin++;
}
}
}
复杂度:O(m * n); m是行数,n是列数
搜索无序/搜索最佳匹配:此函数查找存在给定数字序列的所有行(数字顺序无关紧要)。 在这里,我最初对大型数组进行排序,并且在搜索过程中仅对输入数组进行排序。
void SearchUnordered/BestMatch(std::vector<int> const &match, std::vector<int> const &big_matrix_sorted, int begin, int finish,
int width, std::vector<int> &searchResult) {
std::vector<int>::iterator it;
std::vector<int> v(match.size() + width);
while (begin < finish) {
it = std::set_intersection(match.begin(), match.end(), big_matrix_sorted.begin() + begin * width,
big_matrix_sorted.begin() + begin * width + width, v.begin());
v.resize(it - v.begin());
if (v.size() == subseq.size())
searchResult[begin] = begin;
else
searchResult[begin] = -1;
begin++;
/* For search best match the last few lines will change as follows:
searchResult[begin] = (int) v.size();
begin++; and largest in searchResult will be the result */
}
}
复杂度:O(m *(l + n)); l-模式的长度,m是行数,n是列数。
big_matrix的预处理(构造查找表,存储排序后的版本。您可以进行任何预处理。)未考虑在内 。如何提高这些搜索功能的复杂度( O(log(m * n))?
答案 0 :(得分:2)
如果您想整体上更快,但是已经有了正确的算法。您可以通过仅优化代码来获得一些性能(内存分配,如果编译器不执行,则删除重复的操作等)。例如,通过删除两个big_matrix[(row * width) + i]
并将其分配给局部变量,可以 有所作为。请谨慎描述和衡量实际案例。
要获得更大收益,可以选择使用线程。您可以一次在此处处理一行,因此应该随核数的增加而大致线性提高。 C ++ 11具有std::async
,它可以处理启动线程和获取结果的一些工作,而不是自己处理std::thread
或平台特定的机制。在C ++的较新版本中,还有其他一些较新的东西可能也有用。
void searchPatternRow(std::vector<int> const &pattern, std::vector<int> const &big_matrix, int row, int width, std::vector<int> &searchResult);
void searchPattern(std::vector<int> const &pattern, std::vector<int> const &big_matrix, int begin, int finish, int width, std::vector<int> &searchResult)
{
std::vector<std::future<void>> futures;
for (int row = begin; row < finish; ++row)
std::async([&, row]() { searchPatternRow(pattern, big_matrix, row, width, searchResult); });
for (auto &future : futures) future.wait(); // Note, also implicit when the future from async gets destructed
}
要提高线程效率,您可能需要批处理并搜索10行。对于将线程写入searchResult
的同一缓存行的线程,还有一些注意事项。
答案 1 :(得分:1)
搜索完全匹配时,您可以使用我称之为“ 移动哈希”的方法来高效地完成此操作。
搜索时,您将在搜索字符串上计算哈希,同时,您将继续在要搜索的数据上计算移动哈希。比较时,您首先要比较哈希值,只有匹配时才继续比较实际数据。
现在勾号是选择一种哈希算法,该算法可以在每次移动一个地点时轻松更新,而不是重新计算所有内容。这样的哈希的示例是例如。所有数字的总和。
如果我具有以下数组:012345678901234567890
,并且我想在此数组中找到34567
,则可以将哈希定义为搜索字符串中所有数字的总和。这将得到25
的哈希(3 + 4 + 5 + 6 + 7)。然后,我将搜索整个数组并继续更新该数组上正在运行的哈希。数组中的第一个哈希为10
(0 + 1 + 2 + 3 + 4),第二个哈希为15
(1 + 2 + 3 + 4 + 5)。但是,无需重新计算第二个哈希,我可以通过添加5(新数字)并减去0(旧数字)来更新前一个哈希。
由于更新“正在运行的哈希”为 O(1),因此,如果您有一个不错的Hash算法,并且不会产生很多错误命中,则可以大大加快该过程。我用作哈希的简单总和可能太简单了,但是其他方法允许这种哈希更新,例如 XOR ..