B树与二叉树

Posted

技术标签:

【中文标题】B树与二叉树【英文标题】:B trees vs binary trees 【发布时间】:2011-09-06 20:31:50 【问题描述】:

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

我所知道的是-

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

在各种博客上对此进行了很多讨论。

【问题讨论】:

大概任何给定的搜索只访问每个节点一次,那么缓存会带来什么改进?在不知道节点大小的情况下,甚至无法疯狂推测缓存行大小会提高下一次命中率。 【参考方案1】:

算法复杂度是相同的,因为 O(logb n) = O(c log n) = O(log n) 但常数因子隐藏在 big-O 符号中,根据实现和硬件的不同,可能会有显着差异。

B-trees 是为盘片硬盘设计的,它有很长的访问时间(将磁头移动到位),之后读取整个物理扇区。使 B-tree 节点与扇区一样大,可以最大限度地减少访问次数,并使每次读取操作中的有用数据最大化。

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

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

二叉搜索树将有 220 个节点,每个节点都有一个键和两个指针(3 个字)。深度将是 log2(220) = 20。平均搜索必须从根节点读取路径中每个节点的键和指针之一一路向下 = 40 个字

为硬盘制作的 B-tree 将有 4kB 节点。每个节点可以在内部存储为键和指针对的排序数组,在​​ 256 和 512 之间。平均搜索会是什么样子?考虑平均 3/4 填充,每个节点将包含 384 个条目,其内部二进制搜索平均必须访问 log2(384) = 5.95 个键。平均深度将为 log384(220) = 2.33,因此我们的搜索平均需要读取 2.33 次 5.95 个键,或大约 14 个词。

在低扇出(分支因子)B-tree 的情况下,每个节点持有 16 到 32 个键,平均填充将是 24 个键,平均深度 log24( 220) = 4.36,每个节点的二分查找都会做log2(24) = 4.58的比较,整体平均查找要读一下 20 字

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

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

无论如何,似乎只有内存的 B 树具有低扇出 appear to perform better than binary trees in practice。

每个节点 32 个键似乎是当前架构的最佳选择,包括 32 位和 64 位。许多较新的语言和库正在使用 32 键 B 树作为内置数据结构,与哈希表和数组一起使用或替代哈希表和数组。这种用法由 Clojure 和其他函数式语言率先使用,但随后被更主流的语言(如 javascript)采用,最近关注不可变数据结构(例如 Immutable.js)

这个结果不仅可以通过计算从内存中读取的字数来解释,还可以通过计算缓存未命中来解释,这是导致 CPU 停止并等待 RAM 的读取操作。如果缓存架构可以一次获取包含整个 B-tree 节点的 RAM 块,我们将获得已成功用于基于磁盘的大容量存储的相同优化。

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

【讨论】:

很好的深度描述。真的很有价值。它清楚地说明了为什么 B 树通常存储在二级内存中会更好 谢谢。它不仅仅是二级内存,它也适用于 L3 缓存。我已经添加了那部分。 不要忘记,今天的处理器缓存行大小通常为 64 字节,磁盘(旋转和 SSD)扇区大小通常为 512 字节... 嗯,通常 B-tree 实现在节点内部进行二分搜索,因此比较次数与 BST 大致相同。低扇出 (5-10-20) 内存中 B 树通常会出现例外情况,因为线性扫描速度更快。 SSD 在每秒随机读取方面与机械磁盘非常相似。请参阅 here 和 here。越来越好,但离记忆还很远。【参考方案2】:

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

【讨论】:

我认为 BTree 的搜索复杂度为 O(log(b) N),其中 B 是树的等级。因此与 O(log(2) N) 相比存在很大差异在性能方面。如果我错了,请纠正我 纠正你,然后:对数的底实际上是对数上的一个常数乘法因子(例如,log10(n) 等于 3.32 * log2(n)),因此它被忽略为像任何其他复杂性类常数因子。在任一类型的树中搜索仍然是 O(log n)

以上是关于B树与二叉树的主要内容,如果未能解决你的问题,请参考以下文章

B树与二叉树

(王道408考研数据结构)第五章树-第三节4:树与二叉树的转换

树与二叉树的相互转换以及森林和二叉树的相互转换

王道数据结构5(树与二叉树)

王道数据结构5(树与二叉树)

考研数据结构与算法树与二叉树