我正在做练习,我应该使用迭代器计算从一系列点到给定查询点的距离。现在我对迭代器很新,所以我希望有人可以为我澄清一些事情。我应该填写的功能是:
// Computes the distances of all points in the range [begin,end) to a given query point.
//
// The results are stored in the Range starting with distanceBegin having the same length
// as the range of points. The i-th element of the range stores the distance of the i-th point
// in the range to the query point as a double value.
//
// The supplied iterators can be assumed to be bidirectional
template<class SetIterator, class DistanceIterator>
void computeDistances(
SetIterator begin, SetIterator end,//pointers to the start and end of the set of points
Vector const& query, //the query point
DistanceIterator distanceBegin //iterator to the beginning of the range storing the distances
)
{
}
我的问题是:我应该如何解决这个问题。我想我应该通过递增然后计算不同点之间的长度作为len(iterated_point-query)来遍历点的范围。但类向量是否有内置迭代器?什么是DistanceIterator。这是我存储距离的结果还是存储这些结果的地方?
答案 0 :(得分:1)
是的,听起来不错! :)我应该如何解决这个问题?我想我应该通过递增然后计算不同点之间的长度作为len(iterated_point-query)来遍历点的范围。
类向量是否具有内置迭代器?
没有任何更多的背景,这是不可能的。但是我会假设在这种情况下Vector
就像一个数学向量(x,y,z,..),并且这些点类似(x,y,z,...)。所以
- [begin, end)
是一个Vector
个对象
- [distanceBegin, distanceBegin + std::distance(begin, end))
是一系列双打。
DistanceIterator究竟是什么?这是我存储距离的结果还是存储这些结果的地方?
是。它是存储距离的数组的第一个元素的迭代器。以下是我认为问题所在的问题
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
// Forward declaration of Vector (provide your own)
struct Vector;
// Converts a Vector object to a double, by calculating the distance between
// it and the origin using Pythagoras' theorem.
double len(const Vector& v) { return std::sqrt(v._x*v._x + v._y*v._y + v._z*v._z); }
// Your function
template<class SetIterator, class DistanceIterator>
void computeDistances(
SetIterator begin, SetIterator end,
Vector const& query,
DistanceIterator distanceBegin
)
{
std::transform(begin, end, distanceBegin, [query](Vector& v) { return len(v - query); });
}
使用lambda的std :: transform等同于
for (; begin != end; ++begin, ++distanceBegin)
{
*distanceBegin = len(*begin - query);
}
为了使这项工作,您应该提供自己的Vector实现,并相应地更改函数+ lambda。 Here is my minimal and very simplistic implementation of this code.
我应该补充说,有很多更好的方法来编写computeDistances函数。首先,我们operator - ()
每次调用它时都会创建一个额外的Vector,所以让我们重写len(),使其使用元素进行减法
double len(const Vector& v1, const Vector& v2)
{
return std::sqrt(v1._x*v2._x + v1._y*v2._y + v1._z*v2._z);
}
然后让我们用
替换非常冗长且难以阅读的computeDistances// Solution 1 : simple and concise, but prone to one-off errors
for (unsigned i = 0; i < points.size(); ++i)
{
distances[i] = len(points[i], query);
}
// Solution 2
// Get indices implementation from https://github.com/klmr/cpp11-range
for (unsigned i : indices(points))
{
distances[i] = len(points[i], query);
}
如果您想要最通用的解决方案,那么您可以使用模板启动代码并使其与容器无关,尽管这非常详细。 I had a go at making such a thing here.
答案 1 :(得分:0)
我建议您查看std::transform
以及它是如何运作的:http://en.cppreference.com/w/cpp/algorithm/transform
您很快就会注意到相似性:需要从begin
迭代到end
,并且每个元素执行一次计算(在您的情况下距离query
)。采用范围[begin, end[
中的元素的计算结果将使用给定的输出迭代器(distanceBegin
)进行存储,因为它是将保存计算结果的集合中的迭代器。
为了让您前进,请考虑以下示例:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
// Range of elements over which we need to iterate
auto myRange = {1, 2, 3};
auto begin = std::begin(myRange);
auto end = std::end(myRange);
// Reference element
auto reference = 2.0;
// Container holding result and iterator into that container
std::vector<double> results;
auto output = std::back_inserter(results);
// Lambda function performing the calculation: for a given element, a simple calculation is made w.r.t. to a reference value
auto calculation = [&reference](const int &element){ return element - reference; };
// Perform the calculation
std::transform(begin, end, output, calculation);
// Print out the results
for (const auto &result : results) {
std::cout << result << std::endl;
}
}
此示例使用C ++ 11功能(auto
和lambdas
),但这些并不是严格要求的,可以很容易地适应C ++ 03。
如您所见,std::transforms
遍历范围[begin, end[
的元素并使用解除引用的迭代器调用calculation
(即它传递&#39;当前&#39;迭代器引用的元素并使用给定的输出迭代器存储结果。
现在,在您的情况下,您基本上需要编写一个函数来执行std::transform
所做的事情,但针对您的具体情况。