两个数组之间最近点的索引

时间:2011-06-27 16:09:33

标签: c++ stl

给定两个向量foobar,我想输出一个长度为foo.size()的向量,其中包含索引到“最近”的bar元素。我不喜欢重新发明轮子 - 是否有任何STL算法或其他简洁的做法?

#include <vector>
#include <cmath>
#include <float.h>

int main() {
    vector<double> foo;
    vector<double> bar;

    // example data setup
    double array_foo[] = {0.0, 1.0, 2.0, 3.0, 4.0,
                          5.0, 6.0, 7.0, 8.0, 9.0};
    double array_bar[] = {4.8, 1.5, 12.0};
    foo.assign(array_foo, array_foo + 10);
    bar.assign(array_bar, array_bar + 3);

    // output array
    vector<int> indices;
    indices.resize(foo.size());

    for(int i = 0; i < foo.size(); i++) {
        double dist = DBL_MAX;
        int idx = 0;
        // find index of closest element in foo
        for(int j = 0; j < bar.size(); j++) {
            if(abs(foo[i] - bar[j]) < dist) {
                dist = abs(foo[i] - bar[j]);
                idx = j;
            }
        }
        indices[i] = idx;
    }
    // expected result: indices = [1,1,1,1,0,0,0,0,0,2]
    return 0;
}

3 个答案:

答案 0 :(得分:3)

我看到3种不同的解决方案。它们都提供相同的复杂度O(N * logN)。

1

如果bar在二叉树(std::map)中存储元素。然后,对于foo中的每个元素,您必须找到最多两个边界元素,并从中选择最佳元素。

构建树是O(N * logN),第二遍是O(N * logN)

2

与上面相同,除了使用二叉树之外,您可以使用排序数组。创建一个数组,其中每个元素由bar元素及其索引组成(或者您的数组应包含指向bar元素的指针)。然后,您将进行数组搜索,而不是树搜索。

从复杂的角度来看,这是完全相同的。然而,实际上在排序数组中搜索可能会更快一些。

3

foobar进行排序。 (再次,您必须在排序数组中拥有原始索引,或者只存储指向原始元素的指针。

现在,对于排序foo中的每个元素,您都不必在bar中进行完整搜索。相反,您应该只检查是否应该保持在排序bar的当前位置或继续前进。

答案 1 :(得分:2)

这个确切的算法不存在,但您可以使用std::min_element和自定义仿函数以惯用的STL方式实现它:

template <typename T>
T norm(const T& a, const T& b)
{
    return abs(b - a);
}

template <typename T>
struct closer_compare
{
    closer_compare(const T& to) : to(to) {}
    bool operator()(const T& a, const T& b) const
    {
        return norm(a, to) < norm(b, to);
    }
    const T& to;
};

template <typename It1, typename It2, typename OutIt>
void find_nearest_indices(It1 in1_begin, It1 in1_end, It2 in2_begin, It2 in2_end, OutIt out)
{
    typedef typename std::iterator_traits<It1>::value_type value;
    for (It1 it = in1_begin; it != in1_end; ++it)
    {
        It2 closest = std::min_element(in2_begin, in2_end, closer_compare<value>(*it));
        *out++ = std::distance(in2_begin, closest);
    }
}

您的算法将替换为:

find_nearest_indices(foo.begin(), foo.end(), bar.begin(), bar.end(), indices.begin());

我测试了你的输入并得到了你期望的结果。

答案 2 :(得分:0)

如果您知道数组已排序,或者您是否允许对数组进行排序,则可以使用STL lower_boundupper_bound算法进行二进制搜索以查找第一个中的第二个数组。返回的迭代器将指向第一个元素,该元素至少与您的元素一样大(或严格地大于upper_bound的情况),将元素数量限制为需要检查的第一个数组。这将在O(m lg n)中运行,其中m是第二个数组中元素的数量,n是第一个数组中的数字。