【问题标题】:Find the closest point from list to one referent list从列表中查找到一个参考列表的最近点
【发布时间】:2017-04-04 21:12:54
【问题描述】:

我有成对的 int 坐标列表,例如

list<pair<int,int> > coordinates;

我需要找到离一个点原点最近的点,

class Point{
public:
float x;
float y;
};

我可以使用自定义比较器对象和排序找到,但我想知道 min 是否有更快的方法?我试过了

class DistanceComparator{
public:
    DistanceComparator(const Point& p){origin=p;}
    inline bool operator<(std::pair<int,int> & lhs,std::pair<int,int > & rhs)
    {
        float deltaX1=lhs.first-origin.x;
        float deltaY1=lhs.second-origin.y;
        float deltaX2=rhs.first-origin.x;
        float deltaY2=rhs.second-origin.y;
        return (deltaX1*deltaX1+deltaY1*deltaY1)<(deltaX2*deltaX2+deltaY2*deltaY2);
    }
private:
    Pointorigin;
};

但是

【问题讨论】:

    标签: c++ algorithm stl


    【解决方案1】:

    您的解决方案不是最理想的,因为它需要对整个列表进行排序,而这并不是必需的。你只需要最小的元素,其余的不需要排序。我是否建议您查看std::partial_sort 或只是去突击队并遍历它(O(n) 而不是O(n*log(n)) 排序)。

    【讨论】:

    • 还有 std::nth_element (线性复杂度平均值)
    【解决方案2】:

    正如 Luchian Grigore 已经说过的,您不应该对点列表进行排序。不过,我想在这里解决您的语法问题。

    您不能将比较运算符用作比较两个 other 对象的类 member。您只有两种可能来定义比较运算符:

    1. 一个成员函数bool T::operator&lt;(const U&amp; rhs) const,其中this 是左侧操作数。 (我认为 const-reference 是可选的,但当然强烈推荐。)请注意,T == U 不一定是真的。

    2. 非成员函数 bool operator&lt;(const T&amp; lhs, const U&amp; lhs) const 再次与 T == U 不一定是真的。

    所以您不能拥有一个比较运算符,它可以访问您想要的三个对象:两个操作数,有点像可以参数化的“上下文” > 比较。

    为了解决这个问题,我知道以下两种解决方案(可能不止这些):

    1. 开始使用比较运算符时,将附加参数设置为全局变量。当然,这很脏(全局变量在 OOP 中总是脏的)并且使排序不可重入。由于它太脏了,我永远不会推荐它(但它仍然是一个可能的解决方案),因此我不会在这里给出示例代码。

    2. 使用谓词而不是operator &lt;。有多种方法可以做到这一点。这里有两个:

      如果你有 c++0x / c++11 可用: 使用一个 lambda 函数,它可以从客户端上下文(运行 @ 987654327@):

      Point origin = ...;
      std::sort(..., [origin](const Point & a, const Point & b){
          return distance(a, origin) < distance(b, origin);
      });
      

      如果您没有可用的 c++0x / c++11: 您仍然可以定义自定义谓词以自定义方式比较两个对象,而无需 lambda 函数。你必须定义一个比较器帮助类:

      // Helper class:
      struct PointDistanceComparator {
          PointDistanceComparator(Point origin) : origin(origin) {}
          bool operator() (const Point & a, const Point & b) const {
              return distance(a, origin) < distance(b, origin);
          }
      private:
          Point origin;
      };
      
      // Client code:
      Point origin = ...;
      std::sort(..., PointDistanceComparator(origin));
      

      当然,您可以(就像您所做的那样)优化代码以不使用平方根来计算距离。示例代码应该只让您了解如何对比较进行参数化。

    【讨论】:

      【解决方案3】:

      如果您需要多次查询坐标列表,您可能需要考虑使用 Kd-tree 进行最近邻搜索。这将具有 O(log n) 时间复杂度。 构建和查询 Kd 树大约需要 15-20 行(可读)C++ 代码。 看看Kd-tree wikipedia article 还可以查看std::nth_element,您可以使用它来有效地构建您的 Kd-tree(选择枢轴点并对容器进行分区(左右子项,请参阅维基百科文章中的 python 代码)。

      更新:我使用 K-最近邻搜索创建了一个 C++ N-dimensional K-d tree implementation。它包括一些单元测试,向您展示如何使用它。

      【讨论】:

      • +1 用于几何数据结构!或者QuadTree。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多