B树与二叉树

时间:2011-06-02 06:14:48

标签: performance binary-tree b-tree

如果我使用b树实现内存(RAM)搜索操作,那么与二叉树相比,它在缓存或其他一些效果方面会更好吗?

我所知道的是

binary search tress---O(log n)
btrees ---------------O(c log n)

在各种博客上有很多关于这方面的讨论。

2 个答案:

答案 0 :(得分:46)

算法复杂度是相同的,因为O(log b n)= O(c log n)= O(log n)但是常数因子,隐藏在big-O表示法中,可能会有明显不同,具体取决于实施和硬件。

B树被设计用于盘片硬盘,其具有大的访问时间(将头部移动到位),之后读取整个物理扇区。使B树节点与扇区一样大,可以最大限度地减少访问次数,并最大化每次读取操作中的有用数据。

但是如果您的内存不足,则访问时间可以忽略不计,因此更好的比较是计算算法访问的单个单词的数量。

例如,让我们计划一个数据结构来存储每个1个字的2个 20 键,在32位机器上总共有4MiB的原始数据。

二叉搜索树将有2个 20 节点,每个节点包含一个键和两个指针(3个字)。深度将是log 2 (2 20 )= 20.平均搜索将必须从根路径读取密钥和其路径中每个节点的指针之一一直向下= 40字

为硬盘制作的B树将具有4kB节点。每个节点可以在内部存储为键和指针对的排序数组,在​​256和512之间。平均搜索结果是什么样的?考虑到平均3/4填充,每个节点将包含384个条目,并且其内部二进制搜索将必须访问平均log 2 (384)= 5.95个密钥。平均深度将为log 384 (2 20 )= 2.33,因此我们的搜索必须平均读取2.33倍5.95键,或大约 14个字< /强>

在低扇出(分支因子)B树的情况下,每个节点保持在16到32个键之间,平均填充将是24个键,平均深度log 24 ( 2 20 )= 4.36,每个节点的二进制搜索将使log 2 (24)= 4.58比较,并且整体平均搜索将不得不读取 20个字

请记住,最后两个数据结构比二叉树获得更好的结果,因为它们优化读取操作而非修改。要将密钥插入其中一个B树中,您必须平均重写整个384字或24字节点(如果不超过一个),而在二叉树情况下,写操作仍然只需要最多可达40个单词。

(之前我错了。感谢@virco和@Groo在评论中指出我的错误。)

在任何情况下,似乎只有内存的B树,扇出率低appear to perform better than binary trees in practice

特别是每个节点32个密钥似乎是当前架构的最佳选择,无论是32位还是64位。许多较新的语言和库使用32键B树作为内置数据结构,或者作为哈希表和数组的替代品。这种用法由Clojure和其他函数式语言引领,但随后被更多主流语言(如Javascript)所采用,最近关注不可变数据结构(例如Immutable.js

这个结果不仅可以通过计算从内存中读取的字数来解释,而且缓存也会错过,这些读操作会导致CPU停顿并等待RAM。如果缓存体系结构可以一次获取包含整个B树节点的RAM块,我们将获得与基于磁盘的大容量存储成功使用的相同优化。

在硬盘优化数据结构的情况下,我们将使用具有与物理磁盘扇区一样大的节点的B树,以最小化磁盘访问时间。在这种情况下,我们使用B树,其节点与3级缓存对RAM执行的读取操作一样大,以最大限度地减少缓存未命中。

答案 1 :(得分:7)

B-trees与二叉树的不同之处在于,键和指针聚集在内存中,因此在磁盘和内存中都可以获得更好的缓存行为。但是渐近(big-O)运行时没有区别。