【问题标题】:Heap or Red-Black Tree?堆还是红黑树?
【发布时间】:2013-07-16 12:30:55
【问题描述】:

我愿意用一个数据结构作为常数空间的溢出缓冲区。我想要有效地插入,但最重要的是有效地删除 min 元素。我正在考虑使用堆,因为我有 O(log(n)) find_min() 和 log(n) 插入和删除。另一方面,我不明白与红黑树相比的优势,因为它也有 O(log(n)) 插入和删除,但 O(1) 找到最小值/最大值。以及排序输出的优势(我不在乎)。

问题涉及到:Is a red-black tree my ideal data structure?

既然我可以从 std::map 和 boost::heap 获得两种结构,为什么我应该更喜欢使用堆而不是红黑树? 最后,使用红黑树,我还有 O(log(n)) 搜索条目的时间,而对于堆,时间是 O(n),这很重要,因为存在重复。

【问题讨论】:

标签: c++ algorithm data-structures red-black-tree binary-heap


【解决方案1】:

堆很容易在连续内存中实现,即数组。红黑树通常是为每个节点分配一个单独的堆来构造的。红黑树最终会在每次树遍历时访问整个堆的内存。这是最坏情况下的缓存行为。尽管两种结构的某些操作的算法复杂度相同,但红黑树的恒定开销要高得多。

【讨论】:

    【解决方案2】:

    区别主要在于您将如何使用这些结构。

    • 二进制堆是用于插入值和检索最小值的非常快速的数据结构。但是,它们不支持有效搜索或删除随机值。

    • 红/黑树是平衡的二叉搜索树,支持高效的插入、删除、任意值的查找和(相当快的)查找最小值。但是,与二进制堆相比,它们的开销很大。

    如果您只需要插入、查找最小值和删除最小值,那么二进制堆可能是一个更好的选择,因为开销较低并且运行时应该更快。如果您需要插入和删除任意值或查找任意值,红/黑树可能是更好的选择。与所有工程一样,选择正确的数据结构需要权衡取舍。

    另外,请注意,如果您需要二进制堆,可以使用std::priority_queue;你不需要使用Boost。也不能保证std::map 是红/黑树;它可能是某种平衡的 BST,但可以使用其他算法进行平衡。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的快速回答。在我的数据中,我有重复项,所以我无法避免 find() 在堆上很昂贵。另一方面,插入和擦除在堆中更快,但在红黑树中是对数的。我想红黑树是这个的正确答案。但是,我在一篇论文中看到使用堆,即使他们有 find() 操作,这就是我感到困惑的原因。
    • 堆不是搜索数据结构;但是,您可以将元素的位置存储在堆内,以便稍后您可以更改其优先级(这将相应地向上或向下移动元素)。许多基于扫描线的几何算法都需要这种“查找和更新”。
    • 补充 DanielKO 所说的,我曾经看到一个自定义的二进制堆,它在项目本身中维护每个项目的索引。创建者只对启用 (items[item.index] == item) 的 O(1) 包含感兴趣,但您也可以使用它来大大加快其他操作。