我有一对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;
};
但是&lt;只需要一个参数。怎么做?
答案 0 :(得分:5)
您的解决方案不是最佳的,因为它需要对整个列表进行排序,这是不需要的。您只需要最小元素,不需要对其余元素进行排序。我可能建议你研究std::partial_sort
或者只是去突击队员并进行迭代(O(n)
而不是O(n*log(n))
排序)。
答案 1 :(得分:2)
正如Luchian Grigore所说,你不应该对点数进行排序。但是,我想在这里解决你的语法问题。
您不能将比较运算符作为类成员来比较两个其他对象。您只有两种可能性来定义比较运算符:
成员函数bool T::operator<(const U& rhs) const
,其中this
是左侧操作数。 (const-reference是可选的,我认为,但当然强烈推荐。)请注意T == U
不一定是真的。
非成员函数bool operator<(const T& lhs, const U& lhs) const
再次与T == U
不一定是真的。
所以你不能有一个比较运算符,它可以访问你想拥有的三个对象:两个操作数,有点像“上下文”,可以参数化比较。
为了解决这个问题,我知道以下两个解决方案(可能还有更多):
开始使用比较运算符时,将附加参数设置为全局变量。当然,这非常脏(全局变量在OOP中总是很脏)并且使排序不可重入。由于它太脏了我永远不会推荐它(但它仍然是可能的解决方案),因此我不会在这里给出示例代码。
使用谓词而不是operator <
。有多种方法可以做到这一点。这是两个:
如果你有c ++ 0x / c ++ 11可用:使用 lambda函数,它可以从客户端上下文中获取附加参数(你在哪里运行{ {1}}):
std::sort
如果您没有可用的c ++ 0x / c ++ 11:您仍然可以定义自定义谓词,以便在没有lambda函数的情况下以自定义方式比较这两个对象。您必须定义比较器辅助类:
Point origin = ...;
std::sort(..., [origin](const Point & a, const Point & b){
return distance(a, origin) < distance(b, origin);
});
当然,你可以(像你一样)优化代码,不使用平方根来计算距离。示例代码只能让您了解如何对比较进行参数化。
答案 2 :(得分:1)
如果您需要多次查询坐标列表,可能需要考虑使用 Kd-tree 进行最近邻搜索。这将具有 O(log n)时间复杂度。
构建和查询Kd树大约是15-20行(可读)C ++代码。
看看Kd-tree wikipedia article
另请查看std::nth_element
,您可以使用它来有效地构建您的Kd树(选择枢轴点并对容器进行分区(左右childeren,请参阅维基百科文章中的python代码)。
更新:我使用K最近邻搜索创建C++ N-dimensional K-d tree implementation。它包括一些单元测试,向您展示如何使用它。