sco*_*doo 5 c++ arrays algorithm loops matching
我目前有一个解决方案,但我觉得它不像这个问题那样有效,所以我想看看是否有更快的方法.
我有两个数组(例如std :: vectors).两个数组只包含排序但值稀疏的唯一整数值,即:1,4,12,13 ......我想问的是有什么快速的方法可以找到INDEX到其中一个值的数组是相同的.例如,array1的值为1,4,12,13,array2的值为2,12,14,16.array2中的第一个匹配值索引为1.数组的索引是重要的,因为我有其他数组包含将使用"匹配"的索引的数据.
我不仅限于使用数组,也可以使用地图.我只比较了两个数组一次.在第一次匹配传球后,它们不会再次被重复使用.在任一阵列中都可以有小到大的值(300,000+),但是不要总是具有相同数量的值(这会使事情变得更容易)
更糟糕的情况是线性搜索O(N ^ 2).使用map会让我更好O(log N),但我仍然会将数组转换为值的映射,索引对.
我目前不做任何容器类型转换的是这个.循环遍历两个数组中较小的一个.将小数组(array1)的当前元素与大数组(array2)的当前元素进行比较.如果array1元素值大于array2元素值,则递增array2的索引,直到它不再大于array1元素值(while循环).然后,如果array1元素值小于array2元素,则转到下一个循环迭代并再次开始.否则它们必须相等,并且我的索引是匹配值的任一数组.
所以在这个循环中,如果所有值都匹配,我最好是O(N),如果没有匹配,则最好是O(2N).所以我想知道是否有更快的东西?很难确定这两个阵列的匹配频率,但我希望我更倾向于大多数阵列,而不是大多数阵列.
我希望我能够很好地解释这个问题,并感谢任何有关改进这一问题的反馈或提示.
代码示例:
std::vector<int> array1 = {4,6,12,34};
std::vector<int> array2 = {1,3,6,34,40};
for(unsigned int i=0, z=0; i < array1.size(); i++)
{
int value1 = array1[i];
while(value1 > array2[z] && z < array2.size())
z++;
if (z >= array2.size())
break; // reached end of array2
if (value1 < array2[z])
continue;
// we have a match, i and z indices have same value
}
Run Code Online (Sandbox Code Playgroud)
结果将是array1 = [1,3]和array2 = [2,3]的匹配索引
我使用一种算法编写了该函数的实现,该算法在稀疏分布上比简单的线性合并表现更好。
\n\n对于发行版,类似于\xe2\x80\xa0的分布,它具有 O(n) 复杂度,但在分布差异很大的范围内,它的性能应低于线性,在最佳情况下接近 O(log n)。然而,我无法证明最坏情况并不比 O(n log n) 更好。另一方面,我也未能找到最坏的情况。
\n\n我对其进行了模板化,以便可以使用任何类型的范围,例如子范围或原始数组。从技术上讲,它也适用于非随机访问迭代器,但复杂性要高得多,因此不推荐。我认为在这种情况下应该可以修改算法以回退到线性搜索,但我没有打扰。
\n\n\xe2\x80\xa0通过类似的分布,我的意思是这对数组有很多交叉点。通过穿越,我的意思是如果您要将两个数组按排序顺序合并在一起,您将从一个数组切换到另一个数组。
\n\n#include <algorithm>\n#include <iterator>\n#include <utility>\n\n// helper structure for the search\ntemplate<class Range, class Out>\nstruct search_data {\n // is any there clearer way to get iterator that might be either\n // a Range::const_iterator or const T*?\n using iterator = decltype(std::cbegin(std::declval<Range&>()));\n iterator curr;\n const iterator begin, end;\n Out out;\n};\n\ntemplate<class Range, class Out>\nauto init_search_data(const Range& range, Out out) {\n return search_data<Range, Out>{\n std::begin(range),\n std::begin(range),\n std::end(range),\n out,\n };\n}\n\ntemplate<class Range, class Out1, class Out2>\nvoid match_indices(const Range& in1, const Range& in2, Out1 out1, Out2 out2) {\n auto search_data1 = init_search_data(in1, out1);\n auto search_data2 = init_search_data(in2, out2);\n\n // initial order is arbitrary\n auto lesser = &search_data1;\n auto greater = &search_data2;\n\n // if either range is exhausted, we are finished\n while(lesser->curr != lesser->end\n && greater->curr != greater->end) {\n // difference of first values in each range\n auto delta = *greater->curr - *lesser->curr;\n\n if(!delta) { // matching value was found\n // store both results and increment the iterators\n *lesser->out++ = std::distance(lesser->begin, lesser->curr++);\n *greater->out++ = std::distance(greater->begin, greater->curr++);\n continue; // then start a new iteraton\n }\n\n if(delta < 0) { // set the order of ranges by their first value\n std::swap(lesser, greater);\n delta = -delta; // delta is always positive after this\n }\n\n // next crossing cannot be farther than the delta\n // this assumption has following pre-requisites: \n // range is sorted, values are integers, values in the range are unique\n auto range_left = std::distance(lesser->curr, lesser->end);\n auto upper_limit =\n std::min(range_left, static_cast<decltype(range_left)>(delta));\n\n // exponential search for a sub range where the value at upper bound\n // is greater than target, and value at lower bound is lesser\n auto target = *greater->curr;\n auto lower = lesser->curr;\n auto upper = std::next(lower, upper_limit);\n for(int i = 1; i < upper_limit; i *= 2) {\n auto guess = std::next(lower, i);\n if(*guess >= target) {\n upper = guess;\n break;\n }\n lower = guess;\n }\n\n // skip all values in lesser,\n // that are less than the least value in greater\n lesser->curr = std::lower_bound(lower, upper, target);\n }\n}\n\n#include <iostream>\n#include <vector>\n\nint main() {\n std::vector<int> array1 = {4,6,12,34};\n std::vector<int> array2 = {1,3,6,34};\n\n std::vector<std::size_t> indices1;\n std::vector<std::size_t> indices2;\n\n match_indices(array1, array2,\n std::back_inserter(indices1),\n std::back_inserter(indices2));\n\n std::cout << "indices in array1: ";\n for(std::vector<int>::size_type i : indices1)\n std::cout << i << \' \';\n\n std::cout << "\\nindices in array2: ";\n for(std::vector<int>::size_type i : indices2)\n std::cout << i << \' \';\n std::cout << std::endl;\n}\nRun Code Online (Sandbox Code Playgroud)\n