b+tree数据结构可视化_数据结构: B+Tree及其应用

在前面的文章中我们已经介绍了B-Tree的一些特性,以及B-Tree的插入及删除操作。今天我们介绍一下B-Tree的一个变种 --> B+Tree。B+Tree是一种非常重要的数据结构,它广泛应用于文件系统,及数据库索引中。既然它是B-Tree的一个变种,自然他有很多特性和B-Tree就是一样的,但它们也有以下两点不同:

第一:在 B-Tree中一个含有n个子树的节点有n-1个关键字(key)。而在 B+Tree中一个含有n个子树的节点有n个关键字(key)。为什么在拥有同样子树的情况下B+Tree的节点多需要一个key呢?那是因为 B+Tree的节点会存储该节点的子树中最小的key。

第二:B-Tree的每个节点都包含了关键字(key)以及指向包含这些关键字记录的指针。而 B+Tree在叶子节点中存储了所有的关键字信息,以及指向包含这些关键字记录的指针。而且这些叶子节点构成一个有序链表,即每个叶子节点会有一个指针指向其兄弟节点。在非叶子节点中只存储了关键字信息。下面这张图画的非常好,是我从百度图片搜索而来。相信我们对照这张图看就非常清楚了。

了解了B-Tree和B+Tree的结构后,我们来看看为什么文件系统和数据库索引大量采用这种数据结构。就拿数据库的索引来说,需要创建索引一般数据量都较大,那么创建出来的索引文件也会很大,所以索引一般不可能直接存储在内存中,而是存储在硬盘上(这里我们考虑的是机械硬盘)。我们都知道硬盘的读写速度是远远赶不上内存的,一般都差了几个数量级(机械硬盘读写速度慢主要就是因为它需要通过机械臂将磁头移动到数据所在的磁道上,要详细了解磁盘的原理可以阅读这篇文章Code-lover's Learning Notes)。而我们根据索引来查询就会产生硬盘 I/O,所以要提高查询的性能就必须降低 I/O 的次数(就是要减少磁头移动的次数)。那么B树相对于其它的数据结构如AVL树,红黑树,在降低 I/O 的次数方面有什么优势呢?很明显由于B树的每一个节点能存储多个关键字信息(实际应用中每个节点都能存储几百个关键字信息,当然这个数字也不会非常大,因为它需要保证每个节点的所有关键字能在一次 I/O中就全部读取到内存中,如果需要多次 I/O 的话,那就反而会降低性能。一次 I/O 读取的数据一般为1页,而在大多数操作系统中1也=页的大小为 4 K,所以每个节点存储的关键字信息的总大小不能超过 4K)而二叉树每个节点只能存储一个关键字信息,所以在数据量很大的情况下,二叉树的高度会很大。例如根据我们前面推导的B树的一个公式,N = 1 + s * ((m/2) - 1) = 2 * (

) - 1,一个200阶的高度为4的B树最少能存储2百万个关键字信息。而同样存储2百万个关键字信息则需要一颗高度为21的二叉树。所以在这个200阶的包含2百万个关键字信息的B树中查询 I/O 的次数不会超过3次(因为根节点是常驻内存的),而同样存储2百万个关键字信息的二叉树则可能需要好几倍次数的 I/O 性能就会差很多。

在数据库索引的实现中,大部分采用的是B+Tree而不是B-Tree,这又是为什么呢?

原因有二,其一是由于B+Tree 在非叶子节点中只存储了关键字信息,而没有存储指向包含这些关键字记录的指针,所以在树的高度相同时,B+Tree往往能比B-Tree存储更多的关键字信息。更最要的原因是因为 B+Tree在叶子节点中存储了所有的关键字信息,以及指向包含这些关键字记录的指针。而且这些叶子节点构成一个有序链表,这样B+Tree在实现范围查询的时候就比较容易,只需要遍历这个有序链表就行。而B-tree要实现范围查询则比较困难,但范围查询又是数据库中比较常用的功能,所以数据库中大部分采用的是B+Tree而不是B-Tree。当然B-Tree也有强于B+tree的地方,例如在随机查询中,由于B-Tree的每个节点都包含了关键字(key)以及指向包含这些关键字记录的指针,所以B-Tree可能中途就查询到需要的数据,不需要遍历到叶子节点。而B+Tree由于只在叶子节点中存储了所有的关键字信息,以及指向包含这些关键字记录的指针。在非叶子节点中只存储了关键字信息,没有存储指向包含这些关键字记录的指针,所以B+Tree一定要遍历到叶子节点才能获取到包含这些关键字记录的指针。所以B-Tree的随机查询性能会高于B+Tree。

在B+树的基础上又演变出B*树,B*Tree在非叶子结点中也增加了指向兄弟节点的指针,并且它将非叶子节点上存储的关键字个数的最小值提高到 (2/3) * m,这样的话就提高了空间利用率。

你可能感兴趣的:(b+tree数据结构可视化)