【问题标题】:Why heaps instead of a sorted container为什么堆而不是排序容器
【发布时间】:2013-11-10 23:43:28
【问题描述】:

我正在研究 c++ stl 算法并试图理解堆算法(make_heap、sort_heap、push_heap 等)。我了解它创建的二叉树,以及这对于在任何给定时间有效地查找最高优先级项目有何用处。我不清楚这比维护一个排序容器更好,在这个容器中,价值最高的项目可以简单地从顶部弹出。

这是我所看到的比较:

对于堆:

  • 创建堆:make_heap: O(nlogn) ...错误! O(n)
  • 插入:push_heap:O(logn)
  • 移除最高:pop_heap: O(logn)
  • 获取排序列表:sort_heap: O(nlogn)

对于已排序的容器:

  • 初始排序:sort() O(nlogn)
  • 插入:? O(logn)
  • 移除最高:pop constant
  • 获取排序列表:已排序常量

插入需要找到具有相同值的元素或值两侧的两个元素。在排序列表中,这应该是 O(logn)。我还不知道有什么特定的算法可以做到这一点。

无论如何,我错过了什么?从我上面的分析看来,仅仅维护一个排序的容器在所有情况下都不会更糟,在某些情况下会更好。

谢谢!


编辑:

我想指出这一点,因此没有人会阅读此内容并对我的问题感到困惑。正如 rici 指出的那样,我误解了 make_heap 的复杂性。我最初以为是 O(n log n),但实际上是 O(n)。对我来说,这种差异解释了为什么 make_heap 比简单地维护一个排序列表更好。

【问题讨论】:

  • “排序容器”是指已排序的std::vector 之类的东西吗?因为然后插入是O(n)。或者你的意思是像std::set 这样的容器,它通过在后台使用树结构在内部维护秩序?

标签: c++ algorithm sorting


【解决方案1】:

make_heap 是 O(n),而不是 O(n log n)。对于大型数据集,它可能比排序快很多。

O(log n) 操作(push 和 remove_min)可能只比平衡二叉树实现快一点,但它们的存储开销要低得多,这也提高了它们的缓存友好性。对于像整数这样的小对象,堆使用的内存大约是 std::set 使用的内存的四分之一。

【讨论】:

  • 哇哦!我错过了 make_heap 是 O(n) - 不知何故我认为 n log n。谢谢 - 这为我解决了问题。我将编辑我的问题以指出我的错误。
【解决方案2】:

排序列表的插入不是O(log n),这是最坏的情况O(n),因为您必须移动数组中的元素。

【讨论】:

  • 如果这对列表来说是真的,我会感到惊讶。我可以看到像vector这样的容器就是这种情况。您是在使用一般意义上的“列表”吗?
  • 什么意思?列表通常实现为动态数组或链表。在动态数组中,插入最坏情况需要O(n),而在链表中,搜索需要O(n)最坏情况。
  • std::list 是一个链表。您对采用 O(n) 的搜索提出了一个很好的观点,但这不是您在帖子中提到的 - 您说插入需要移动元素。您是说在排序列表上插入 std::list 需要移动元素吗?我认为这只需要更改一些指针。
【解决方案3】:
  1. 您可能不想要整个排序序列。
  2. 您可能希望快速获取第一项并分散计算负载以在检索时的所有条目中进行排序,而不是预先支付所有费用。
  3. 您可能想要处理一个大于内存容量的集合。一个堆可以产生其自身大小平均为 2N 的排序运行。这种技术用于排序合并程序中,当初始运行的数量支配每次运行的排序时间时。

在这些情况下,堆获胜。

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多