B树比AVL或RedBlack-Tree更快?

时间:2009-03-15 09:20:37

标签: algorithm math data-structures binary-tree

我知道性能永远不是黑白的,通常一个实现在X情况下更快,在Y情况下更慢等等但通常情况下 - B树比AVL或RedBlack-Trees快吗?它们比AVL树(甚至可能是RedBlack-trees?)要复杂得多,但它们更快(它们的复杂性是否得到回报)?

编辑:我还想补充一点,如果它们比等效的AVL / RedBlack树更快(就节点/内容而言) - 为什么它们更快?

9 个答案:

答案 0 :(得分:113)

Sean的帖子(目前接受的帖子)包含几个不正确的声明。对不起肖恩,我不是故意粗鲁;我希望我能说服你,我的陈述是基于事实。

  

他们的使用案例完全不同,因此不可能进行比较。

它们都用于维护一组完全有序的项目,具有快速查找,插入和删除功能。它们具有相同的界面和相同的意图。

  

RB树通常是内存中结构,用于为数据提供快速访问(理想情况下为O(logN))。 [...]

总是 O(log n)

  

B树通常是基于磁盘的结构,因此本质上比内存数据慢。

无意义。在磁盘上存储搜索树时,通常使用B树。那是真的。将数据存储在磁盘上时,访问速度比内存中的数据慢。但是存储在磁盘上的红黑树比存储在内存中的红黑树慢。

你在这里比较苹果和橘子。真正有趣的是比较内存中的B树和内存中的红黑树。

[旁白:B-trees,而不是红黑树,在I / O模型中理论上是有效的。我已经通过实验测试(并验证了)I / O模型进行排序;我希望它也适用于B树。]

  

B树很少是二叉树,节点可以拥有的子节点数通常很大。

要明确的是,B树节点的大小范围是树的参数(在C ++中,您可能希望使用整数值作为模板参数)。

  

当数据发生变化时,B树结构的管理会非常复杂。

我记得他们比红黑树更容易理解(和实施)。

  

B-tree尝试最小化磁盘访问次数,以便数据检索具有合理的确定性。

那是真的。

  

在数据库中查找一些数据所需的4 B树访问权限并不罕见。

有数据吗?

  

在大多数情况下,我会说内存中的RB树更快。

有数据吗?

  

因为查找是二进制的,所以很容易找到一些东西。 B树可以在每个节点上有多个子节点,因此在每个节点上,您必须扫描节点以查找适当的子节点。这是O(N)操作。

每个节点的大小是固定参数,因此即使进行线性扫描,也是O(1)。如果我们超过每个节点的大小,请注意您通常将数组保持排序,使其为O(log n)。

  

在RB树上它是O(logN),因为你正在进行一次比较,然后进行分支。

你在比较苹果和橘子。 O(log n)是因为树的高度最多为O(log n),就像B树一样。

另外,除非你用红黑树玩恶劣的分配技巧,否则猜测B树有更好的缓存行为似乎是合理的(它访问一个数组,而不是遍布整个地方的指针,并且分配较少开销增加内存位置甚至更多),这可能有助于它在速度竞赛中。

我可以指出实验证据表明B树(特别是尺寸参数32和64)对于小尺寸的红黑树非常具有竞争力,并且即使是中等大小的n值也优于它。见http://idlebox.net/2007/stx-btree/stx-btree-0.8.3/doxygen-html/speedtest.html

B树更快。为什么?我猜想这是由于内存局部性,更好的缓存行为和更少的指针追逐(如果不是相同的东西,在某种程度上重叠)。

答案 1 :(得分:91)

答案 2 :(得分:27)

没有什么能阻止只在内存中工作的B-Tree实现。事实上,如果密钥比较便宜,内存中的B-Tree可以更快,因为在一个节点中打包多个密钥会在搜索期间导致较少缓存未命中。有关效果比较的信息,请参阅this链接。引用:“速度测试结果非常有趣,并且显示B +树对于包含超过16,000个项目的树木要快得多。” (B +树只是B树的变种)。

答案 3 :(得分:10)

问题是陈旧但我认为它仍然有用。 JonasKölker和Mecki给出了非常好的答案,但我不认为答案涵盖整个故事。我甚至认为整个讨论都忽略了这一点:-)。

当条目相对较小(整数,小字符串/单词,浮点数等)时,关于B-Trees的说法是正确的。当条目很大(超过100B)时,差异会变得更小/不显着。

让我总结关于B树的要点:

  • 由于内存位置的原因,它们比任何二进制搜索树(BST)更快(导致缓存和TLB丢失更少)。

  • 如果条目相对较多,B树通常更节省空间 小或如果条目大小可变。自由空间管理是 更容易(您分配更大的内存块)和额外的元数据 每个条目的开销较低。 B树将浪费一些空间作为节点 并不总是满满的,但是,它们最终仍然更加紧凑 二进制搜索树。

  • 两者的大O性能(O(logN))相同。此外,如果你在每个B树节点内进行二进制搜索,你甚至会得到与BST相同数量的比较(这是一个很好的数学运算来验证这一点)。     如果B树节点大小合理(1-4倍高速缓存行大小),则每个节点内的线性搜索仍然更快 硬件预取。您也可以使用SIMD说明 比较基本数据类型(例如整数)。

  • B-Trees更适合压缩:每个节点有更多数据要压缩。在某些情况下,这可能是一个巨大的好处。 只需考虑用于构建索引的关系数据库表中的自动递增键。 B树的主节点包含非常非常好地压缩的连续整数。

  • 当存储在二级存储(需要执行阻止IO)时,B树显然要快得多。

在纸面上,B-Tree有许多优点,几乎没有任何缺点。那么应该只使用B树来获得最佳性能吗?

答案通常是否定的 - 如果树适合记忆。在性能至关重要的情况下,您需要一个线程安全的树状数据结构(简单地说,几个线程可以完成比单个线程更多的工作)。使B-Tree支持并发访问比制作BST更成问题。使树支持并发访问的最直接方法是在遍历/修改节点时锁定节点。在B-Tree中,每个节点锁定更多条目,从而产生更多的序列化点和更多的竞争锁。

所有树版本(AVL,Red / Black,B-Tree,其他版本)都有无数的变体,它们在支持并发性方面有所不同。在大学课程中教授或从一些入门书籍中阅读的香草算法几乎从未在实践中使用过。因此,很难说哪棵树表现最好,因为没有关于每棵树背后的确切算法的正式协议。我建议将所提到的树更像是数据结构类,它们遵循某些树状不变量,而不是精确的数据结构。

以B树为例。香草B树几乎从未在实践中使用 - 你无法使其成型!最常用的B-Tree变体是B + -Tree(广泛用于文件系统,数据库)。 B + -Tree和B-Tree之间的主要区别:1)您不在树的内部节点中存储条目(因此在修改存储在内部节点中的条目时,您不需要在树中写高锁) ; 2)您在同一级别的节点之间有链接(因此您在进行范围搜索时不必锁定节点的父节点。)

我希望这会有所帮助。

答案 4 :(得分:8)

Google最近发布了他们的STL容器实现,这些容器基于B树。他们声称,与通过红黑树实现的标准STL容器相比,他们的版本更快,占用的内存更少。 更多详情here

答案 5 :(得分:2)

对于某些应用,B树明显快于BST。 您可以在这里找到树木:

http://freshmeat.net/projects/bps

非常快。它们也比常规BST实现使用更少的内存,因为它们不需要每个节点有2或3个指针的BST基础结构,还有一些额外的字段来保存平衡信息。

答案 6 :(得分:0)

它们处于不同的情况下 - 当树节点需要在存储中保持在一起时使用B树 - 通常是因为存储是磁盘页面,因此重新平衡可能非常昂贵。如果没有此约束,则使用RB树。因此,如果你想实现(比方说)一个关系数据库索引,B树可能会更快,而对于(比如说)内存搜索,RB树可能会更快。

答案 7 :(得分:0)

它们都具有相同的渐近行为,因此性能更多地取决于实现而不是您使用的树类型。 树结构的某种组合实际上可能是最快的方法,其中B树的每个节点完全适合于高速缓存行,并且某种二叉树用于在每个节点内搜索。自己管理节点的内存也可以让你实现更高的缓存局部性,但价格非常高。

就个人而言,我只是使用标准库中的任何内容来处理我正在使用的语言,因为对于非常小的性能提升(如果有的话)来说,这是很多工作。

理论上说...... RB树实际上非常类似于B树,因为它们模拟2-3-4树的行为。 AA树是一种类似的结构,它模拟了2-3棵树。

答案 8 :(得分:0)

此外......红黑树的高度为O(log [2] N),而B树的高度为O(log [q] N),其中ceiling [N]< = q< = N.因此,如果我们考虑在B树的每个关键数组中进行比较(如上所述固定)那么B树的时间复杂度< =红黑树的时间复杂度。 (单个记录的大小与块大小相等)