【问题标题】:Why does a priority queue require front(), pop_back() from the underlying container instead of back(), pop_back()?为什么优先级队列需要底层容器的front()、pop_back()而不是back()、pop_back()?
【发布时间】:2018-06-25 06:07:54
【问题描述】:

来自 C++ Primerhttps://en.cppreference.com/w/cpp/container/priority_queue,我知道:

priority_queue 需要随机访问 除了 front、push_back 和 pop_back 操作;

我还从 Google 阅读了这个 blog post 并知道:

  • push:向队列中添加一个新元素,
  • pop:移除队列中最大的元素,
  • top:访问队列中最大的元素。

push应该由push_back实现,没问题。 而poptop 似乎在同一个元素上运行。一个是访问它,另一个是删除它。所以我觉得这两个操作应该由pop_front()front()或者pop_back()back()来实现。

所以我很困惑,为什么要求front()pop_back()

例如,假设底层容器是 vector 并带有一些 int 元素,比如 1,2,3,4,5,6。适配器接口“pop(),top()”如何与底层的“front(),pop_back()”协同工作?

【问题讨论】:

  • @Someprogrammerdude 我只是无法理解优先级队列的接口与(底层容器的)最小操作要求之间的联系。我的意思是,为什么最不需要的是push_backpop_backfront。 (push_back当然很容易理解)
  • pop 用于删除top 元素。所以我认为底层操作也应该针对相同的元素,对吧?假设vectorpop_back()front() 不针对同一个元素。
  • 我认为这是因为优先队列的实现是通过堆发生的。见stackoverflow.com/questions/2974470/…

标签: c++


【解决方案1】:

虽然priority_queue 上的pop() 最终会删除顶部元素,但它必须保持不变量,如果所有元素都简单地移动就不会发生这种情况。因此,它通过将顶部值从 front() 交换到 back()pop_back()ing 来工作,然后将置换后的值与它的一个孩子交换,直到恢复不变量。

同样,push() 调用 push_back() 然后执行一系列交换,尽管方向相反。

注意:由于 C++ 使用最大堆(与常见约定相反),不变的是任何元素都必须大于它的两个子元素(如果它们存在)。由于大多数有用的问题都涉及最小堆,因此您几乎总是必须将 std::greater<> 指定为 Compare 模板参数。

【讨论】:

  • 抱歉,我对堆知之甚少 (ಥ_ಥ)。据我所知,您是在说:例如我将1,2,3 存储在p 队列中(使用vector)。经过一些排序后,它在内部看起来像 [3][2][1]。当我调用pop时,它变成了[1][2][3](将顶部值交换到后面)然后弹出[3],对吗?
  • 一般来说,插入1, 2, 3后的顺序是3, 1, 2。这是因为在插入2 之后,通过向上移动2 来恢复不变量(我称其为“滴入”,类似于下面描述的“滴入”):2, 1。然后,您插入3 并让它滴流,所以2, 12, 1, 33, 1, 2(交换23)。正如@o11c 所说,在删除时,您交换front()back(),执行pop_back(),然后让新的front(),“涓涓细流”,所以3, 1, 22, 1, 32, 1(完成, 不需要2 流下来,因为它已经 > 比它的(唯一的)孩子)。
  • @Rick 顺便说一下,你可能想看看push_heappop_heap 的描述。 pq 的push() 可以实现为c.push_back(),后跟push_heap()。 pq 的pop() 可以实现为pop_heap(),后跟pop_back()。还有make_heap(),它在从迭代器范围(或initializer_list,如果有这样的构造函数)创建pq 时可能很有用——首先通过从范围复制创建容器,然后make_heap()
  • @ArneVogel 您的详细解释非常有帮助。我读过一些关于堆的东西。结合答案和你的 cmets 现在我对它有一个模糊的理解。谢谢:D。
猜你喜欢
  • 2019-04-23
  • 2010-10-18
  • 2020-09-16
  • 2023-03-07
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多