给定两个向量foo
和bar
,我想输出一个长度为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;
}
答案 0 :(得分:3)
我看到3种不同的解决方案。它们都提供相同的复杂度O(N * logN)。
1
如果bar
在二叉树(std::map
)中存储元素。然后,对于foo
中的每个元素,您必须找到最多两个边界元素,并从中选择最佳元素。
构建树是O(N * logN),第二遍是O(N * logN)
2
与上面相同,除了使用二叉树之外,您可以使用排序数组。创建一个数组,其中每个元素由bar
元素及其索引组成(或者您的数组应包含指向bar
元素的指针)。然后,您将进行数组搜索,而不是树搜索。
从复杂的角度来看,这是完全相同的。然而,实际上在排序数组中搜索可能会更快一些。
3
对foo
和bar
进行排序。 (再次,您必须在排序数组中拥有原始索引,或者只存储指向原始元素的指针。
现在,对于排序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_bound
或upper_bound
算法进行二进制搜索以查找第一个中的第二个数组。返回的迭代器将指向第一个元素,该元素至少与您的元素一样大(或严格地大于upper_bound
的情况),将元素数量限制为需要检查的第一个数组。这将在O(m lg n)中运行,其中m是第二个数组中元素的数量,n是第一个数组中的数字。