【问题标题】:using C++ priority_queue comparator correctly正确使用 C++ priority_queue 比较器
【发布时间】:2017-06-29 07:34:50
【问题描述】:

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

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&lt;Point,vector&lt;Point&gt;,comp&gt; pq;

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

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) 最后将优先队列的内容放入一个vector中并返回。

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

【问题讨论】:

  • 分享一个想法。我们可以使用像四叉树或网格这样的空间划分。所以当中心改变时,我们不需要resort points或重建priority_queue。
  • 为什么需要优先队列? 1. 测量到所有点的距离。将距离点(或点索引)存储到向量中,2 partial_sort 这个向量 3. 复制点到结果
  • public interface ... 你确定是 C++ 吗?

标签: c++ comparator priority-queue


【解决方案1】:

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

使用priority_queue 实现findNearest 函数的关键是要意识到比较器可以是捕获中心参数的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 结构上使用模板。您还可以使用模板在findNearest 函数中使points 容器通用。容器只需要支持迭代即可。

【讨论】:

    猜你喜欢
    • 2018-12-17
    • 2013-04-13
    • 2015-06-17
    • 1970-01-01
    • 2016-05-13
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多