正确使用C ++ priority_queue比较器

时间:2017-06-29 07:34:50

标签: c++ comparator priority-queue

最近在一次采访中提到了这个问题

public interface PointsOnAPlane {

/**
 * Stores a given point in an internal data structure
 */
void addPoint(Point point);

/**
 * For given 'center' point returns a subset of 'm' stored points that are
 * closer to the center than others.
 *
 * E.g. Stored: (0, 1) (0, 2) (0, 3) (0, 4) (0, 5)
 *
 * findNearest(new Point(0, 0), 3) -> (0, 1), (0, 2), (0, 3)
 */
vector<Point> findNearest(vector<Point> points, Point center, int m);

}

这是我使用的方法

1)创建最大堆priority_queue以存储最近的点 priority_queue<Point,vector<Point>,comp> pq;

2)如果优先级队列大小<1,则迭代点向量并推送一个点。米

3)如果size == m,则将队列顶部与当前点进行比较,并在必要时弹出

for(int i=0;i<points.size();i++)
{
    if(pq.size() < m)
    {
       pq.push(points[i]);
    } 
    else
    {
       if(compareDistance(points[i],pq.top(),center))
       {
         pq.pop();
         pq.push(points[i]);
       }
    }
}

4)最后将优先级队列的内容放在向量中并返回。

我应该如何编写comp和compareDistance比较器,它允许我最初存储m个点,然后将当前点与顶部的点进行比较?

1 个答案:

答案 0 :(得分:0)

我认为您的方法可以更改,以便以不同的方式使用priority_queue。代码变得有点复杂,因为for循环中有一个if语句,而这个if语句控制何时添加到priority_queue。为什么不首先将所有点添加到priority_queue,然后弹出m点?让priority_queue完成所有工作。

使用findNearest实现priority_queue函数的关键是要意识到比较器可以是捕获中心参数的lambda。所以你可以这样做:

#include <queue>
#include <vector>
using namespace std;

struct Point { int x, y; };

constexpr int distance(const Point& l, const Point& r)
{
    return (l.x - r.x)*(l.x - r.x) + (l.y - r.y)*(l.y - r.y);
}

vector<Point> findNearest(const vector<Point>& points, Point center, int m)
{
    auto comparator = [center](const Point& l, const Point& r) {
        return distance(l, center) > distance(r, center);
    };

    priority_queue<Point, vector<Point>, decltype(comparator)> pq(comparator);

    for (auto&& p : points) {
        pq.emplace(p);
    }

    vector<Point> result;
    for (int i = 0; i < m; ++i) {
        result.push_back(pq.top());
        pq.pop();
    }

    return result;
}

在采访中,谈论算法中的缺陷也很好。

  • 此实施在O(nlogn)中运行。会有一个聪明的算法可以超过这个运行时间,特别是因为你只需要最接近的m点。
  • 由于队列,它使用O(n)更多空间,我们应该能够做得更好。在这个函数中真正发生的是排序,并且可以就地实现排序。
  • 容易出现整数溢出。一个好主意是使用Point结构上的模板。您还可以使用模板在points函数中使findNearest容器通用。容器只需支持迭代。