使用迭代器计算到给定点的距离

时间:2016-06-07 11:22:52

标签: c++

我正在做练习,我应该使用迭代器计算从一系列点到给定查询点的距离。现在我对迭代器很新,所以我希望有人可以为我澄清一些事情。我应该填写的功能是:

// 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。这是我存储距离的结果还是存储这些结果的地方?

2 个答案:

答案 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功能(autolambdas),但这些并不是严格要求的,可以很容易地适应C ++ 03。 如您所见,std::transforms遍历范围[begin, end[的元素并使用解除引用的迭代器调用calculation(即它传递&#39;当前&#39;迭代器引用的元素并使用给定的输出迭代器存储结果。

现在,在您的情况下,您基本上需要编写一个函数来执行std::transform所做的事情,但针对您的具体情况。