avl 树上的红黑树

Posted

技术标签:

【中文标题】avl 树上的红黑树【英文标题】:Red black tree over avl tree 【发布时间】:2012-11-30 22:20:45 【问题描述】:

AVL 和红黑树都是自平衡的,除了节点中的红色和黑色。选择红黑树而不是 AVL 树的主要原因是什么?红黑树的应用有哪些?

【问题讨论】:

Why is std::map implemented as red-black tree?的可能重复 顺便说一句,Rust 开发人员选择使用B-tree 而不是其中任何一个作为标准有序映射。 【参考方案1】:

选择红黑树而不是AVL树的主要原因是什么?

red-black trees 和AVL trees 都是最常用的balanced binary search trees,它们支持在保证O(logN) time 中插入、删除和查找。但是,两者之间有以下比较点:

AVL 树更严格地平衡,因此提供更快的查找。因此,对于查找密集型任务,请使用 AVL 树。 对于插入密集型任务,请使用红黑树。 AVL 树在每个节点存储平衡因子。这需要O(N) 额外空间。但是,如果我们知道要插入树中的键总是大于零,我们可以使用键的符号位来存储红黑树的颜色信息。因此,在这种情况下,红黑树不会占用额外的空间。

红黑树有哪些应用?

红黑树更通用。它们在添加、删除和查找方面做得相对较好,但 AVL 树的查找速度更快,但添加/删除速度较慢。红黑树用于以下情况:

Java:java.util.TreeMapjava.util.TreeSet C++ STL(在大多数实现中):map、multimap、multiset Linux 内核:完全公平的调度程序,linux/rbtree.h

【讨论】:

In general, the rotations for an AVL tree are harder to implement and debug than that for a Red-Black tree. 不正确。 为了迂腐,C++ 标准不强制std:: map 和朋友使用任何特定的结构。这留给实现了,尽管 libstdc++ 和 Dinkumware 至少使用了红黑树,而且看起来你在实践中是对的。 存储在 AVL 树的每个节点中的平衡因子是两位(-1 / 0 / +1)。红黑树在每个节点中存储一位颜色信息。因此,总共两棵树都需要 O(N) 内存来存储额外信息。 "对于插入密集型任务,使用红黑树。"为什么? AVL树插入最坏的情况只需要旋转一次,而红黑树可能需要两次。 这应该根据 Ben Pfaff 2003 年对 BST 性能的分析进行更新 - AVL 树更通用,性能更好。 Java、C++ 和 Linux 内核选择较慢实现的确切历史原因将很有趣。【参考方案2】:

尝试阅读此article

它提供了关于差异、相似之处、性能等方面的一些很好的见解。

这是文章的引述:

RB-Tree 和 AVL 树一样是自平衡的。它们都提供 O(log n) 的查找和插入性能。

不同之处在于 RB-Trees 保证每个插入操作的 O(1) 次旋转。这就是在实际实现中实际会降低性能的原因。

简化后,RB-Trees 从概念上是 2-3 棵树获得了这一优势,而无需承担动态节点结构的开销。物理上 RB-Trees 实现为二叉树,红/黑标志模拟 2-3 行为

就我自己的理解而言,AVL 树和 RB 树在性能方面相差不远。 RB 树只是 B 树的变体,平衡的实现方式与 AVL 树不同。

【讨论】:

AFIAK,AVL 树每次插入也有 O(1) 旋转。对于 RB-tree 和 AVL - 一次插入可能有 1 次或 0 次旋转。如果发生旋转,算法就会停止。如果没有发生,通常算法会继续从底部到树根检查/重绘节点。因此,有时旋转 O(1) 可能会更好,因为它消除了扫描剩余项目 O(log(n))。因为平均而言,AVL 树进行更多的旋转,所以 AVL 树通常比 RB-tree 2 log(N) 具有更好的平衡 ~1.44 log(N)。【参考方案3】:

多年来,我们对性能差异的理解有所提高,现在在 AVL 上使用红黑树的主要原因是无法获得良好的 AVL 实现,因为它们不太常见,可能是因为它们没有被涵盖在 CLRS 中。

这两种树现在都被视为rank-balanced trees 的形式,但红黑树始终比about 20% in real world tests 慢。 sequential data is inserted 时甚至会慢 30-40%。

所以研究过红黑树但没有研究过AVL树的人倾向于选择红黑树。红黑树的主要用途详见Wikipedia entry for them。

【讨论】:

好笑!在我的阅读中,libavl 文章似乎说 AVL 和 RB 是正面交锋的,而且两者都没有明显优于另一个(哪个更好取决于工作量)。我没有看到任何声称 AVL 总体上快 20% 的说法。【参考方案4】:

这里的其他答案很好地总结了 RB 和 AVL 树的优缺点,但我发现这种差异特别有趣:

AVL 树不支持常量摊销更新成本 [但红黑树支持]

来源:Mehlhorn & Sanders (2008)(第 7.4 节)

因此,尽管 RB 和 AVL 树都保证 O(log(N)) 最坏情况下的查找、插入和删除时间,但在插入或删除节点之后恢复 AVL/RB 属性可以对于红黑树,在 O(1) amortized time 中完成。

【讨论】:

我相信,AVL 树插入具有相同/相似的摊销成本,但会产生更好的平衡树(1.44log(N) vs 2log(N))。同时,AVL树中的删除可能需要更多的旋转。恕我直言,这是在 WAVL en.wikipedia.org/wiki/WAVL_tree 中解决的【参考方案5】:

AVL 树和 RB 树中的插入都需要最多 2 次旋转。来自https://adtinfo.org/:

红黑树的主要优点是,在 AVL 树中,从包含 n 个节点的树中删除一个节点可能需要 log 2 n 次旋转,但在红黑树中删除永远不需要超过 3 次旋转。

【讨论】:

以上是关于avl 树上的红黑树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构~基础2~树《二叉树二叉搜索树AVL树B树红黑树》的设计~红黑树

二叉排序树红黑树AVL树散列表

简述AVL树红黑树B/B+树Trie树

B树B+树红黑树AVL树比较

二叉树红黑树以及Golang实现红黑树

树结构系列:平衡二叉树AVL树红黑树