B+树的几点总结

作者:Vernon
说明:本文主要以列表形式将B+树的特点以及注意点等列出来,主要参考《算法导论》、维基百科、各大博客的内容,结合自己的理解写的,如内容有不当之处,请各位雅正。
出处:http://blog.csdn.net/love_u_u12138
转载请注明出处。

1.前言

B树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树。B树类似于红黑树,但它们在降低磁盘I/O操作数方面要更好一些。现在许多数据库系统使用B树或者B树的变种(B+树和B*树)来存储信息。B树用的比较普遍,许多书籍、博客都有详细的介绍,对于B树的严格定义也相对统一,在这里就不予赘述。
B+树是B树的一种变形,它把所有的卫星数据都存储在叶节点中,内部节点只存放关键字和孩子指针,因此最大化了内部节点的分支因子,所以B+树的遍历也更加高效(B树需要以中序的方式遍历节点,而B+树只需把所有叶子节点串成链表就可以从头到尾遍历)。

以下先放一张我所依据的B+树的图示(这张图有所简化,下面讲完定义后会贴一张更加详细的图,两图本质并无差异):
B+树的图示

2.定义

B+树的定义我没有找到官方的定义(如果有找到的人望告知我),有些定义在论坛还有争议,但是这些并没有多大影响,只是一点小小的差异,下面的定义中有涉及争议的部分我会提及。

B+树的定义如下:
  1. 每个节点node有下面的属性:
    • n个关键字key[1],key[2], … ,key[n],以非降序存放,使得key[1]≤key[2]≤…≤key[n];
    • isRoot,一个布尔值,如果node是根节点,则为TRUE;否则为FALSE;
    • isLeaf,一个布尔值,如果node是叶子节点,则为TRUE;否则为FALSE;
    • Node*类型的parent指针,指向该节点的父节点
  2. 每个内部节点还包含n个指向其孩子children[0],children[1], … , children[n],叶子节点没有孩子。(注:此处有争议,B+树到底是与B 树n-1个关键字有n棵子树保持一致,还是B+树n个关键字的结点中含有n棵子树;两种定义都可以,只要自己实现的时候统一用一种就行。如无特殊说明,以下的都是后者:即n个关键字对应n棵子树);
  3. 内部节点的关键字对存储在各子树中的关键字范围加以分割:如果key[i]为任意一个存储在内部节点中的关键字,childNum[i]为该节点的对应下标的子树指针指向的节点的任意一个关键字,那么
    key[1] ≤ childNum[1] < key[2] ≤ childNum[2] < key[3] ≤ childNum[3] < … < key[n] ≤ childNum[n]
  4. 内部节点并不存储真正的信息,而是保存其叶子节点的最小值作为索引。比如下图,标注1和标注2都是内部节点,里面保存的并不是真正的信息,而是标注3所示的节点中的最小值。(注:此处有争议以最大值作为索引,同样也是不影响的争议)
    内部节点图示

  5. 任何和关键字相联系的“卫星数据(satellite information)” 将与关键字一样存放在叶子节点中,一般地,可能只是为每个关键字对应的”卫星数据”存放一个指针,指针指向存放实际数据的磁盘页,匹配了某个叶子节点的关键字即可通过该指针找到其他对应数据。

  6. 每个叶子节点还有指向下一个节点的指针next,方便遍历整棵B+树。
  7. 每个叶子节点具有相同的深度,即树的高度h。
  8. 每个节点所包含的关键字个数有上界和下界,用一个被B+树的最小度数(minmum degree)的固定整数t≥2来表示这些界:
    • 除了根节点以外的每个节点必须至少有t个关键字。因此,除了根节点以外的每个内部节点至少有t个孩子
    • 每个节点至多有2t个关键字,因此,一个内部节点至多可有2t个孩子。当一个节点恰好有2t个关键字时,称该节点是满的
结合以上的具体定义,下面这张图更加详细的描述了一棵具体的B+树

B+树图示

3.注意点

在B+树的学习与实现过程中,也遇到不少的疑惑之处,现记录如下,持续更新:

  • 内部节点并不存储真正的信息,而是保存其叶子节点的最小值作为索引。每次插入删除都进行更新(此时用到parent指针),保持最新状态。
  • 关于所有叶子节点都处于同一深度是如何实现的?这与B+树具体的插入和删除算法有关。简单解释一下插入时的情况,根据插入值的大小,逐步向下直到对应的叶子节点。如果叶子节点关键字个数小于2t,则直接插入值或者更新卫星数据;如果插入之前叶子节点已经满了,则分裂该叶子节点成两半,并把中间值提上到父节点的关键字中,如果这导致父节点满了的话,则把该父节点分裂,如此递归向上。所以树高是一层层的增加的,叶子节点永远都在同一深度。下面是我实现的B+树中的插入代码的片段:
/** 插入关键字key */
    public void insert(Comparable key, Object obj, BPlusTree tree)
    {
        // 叶子节点则插入
        if (isLeaf) {
            // 不需要分裂直接插入
            if (containsKeyword(key) || keywords.size() < tree.getDegree()) {
                insertInNotFull(key, obj); // 直接插入
                if (parent != null) {
                    parent.updateAfterInsert(tree); // 更新父节点的信息(将最小的值存到父节点的关键字中作为索引)
                }
                // 需要分裂成左右两个节点
            } else {
                splitNode(key, obj, tree);
            }
            // 如果不是叶子节点则继续往下搜索
        } else {
            Node leafNode = downToLeaf(key);        // 逐步向下到对应的叶子节点
            leafNode.insert(key, obj, tree);
        }
    }

4.结语

B+树还有一个最大的好处,方便扫库,B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持。这是数据库选用B+树的最主要原因。 –梁斌

欢迎各位大牛批评指正。PS:我实现了一个小型B+树系统,使用Java写的,支持插入、搜索、遍历B+树,有需要的同学可以去下载。链接奉上:http://download.csdn.net/detail/love_u_u12138/9355677

参考文献
[1].《算法导论》原书第3版中文版
[2].https://zh.wikipedia.org/wiki/B%2B%E6%A0%91(维基百科B+树条目)
[3].http://blog.csdn.net/v_july_v/article/details/6530142(很详细的一篇B树、B+树、R树的博客)
[4].http://www.ruanyifeng.com/blog/2014/07/database_implementation.html(数据库实现的扼要说明)

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Java中的B和B+是两种常用的数据结构,用于在磁盘上存储和管理大量的数据。它们在实现方式和应用场景上有一些区别。 B是一种平衡的多路搜索,它的每个节点可以存储多个关键字和对应的数据。B的特点是所有的叶子节点都在同一层级上,且每个节点的关键字按照升序排列。B适用于磁盘等外存储设备,因为它可以减少磁盘I/O操作的次数,提高数据的读取效率。B的查找、插入和删除操作的时间复杂度都是O(log n)。 B+是在B的基础上进行了一些改进,它也是一种平衡的多路搜索。B+与B的区别在于,B+的非叶子节点只存储关键字,而不存储数据,所有的数据都存储在叶子节点上。叶子节点之间通过指针连接,形成一个有序链表。B+的特点是所有的叶子节点都在同一层级上,并且通过链表可以方便地进行范围查询。B+适用于数据库索引等场景,因为它可以提高范围查询的效率。B+的查找、插入和删除操作的时间复杂度也是O(log n)。 总结一下,B和B+的区别主要有以下几点: 1. B的非叶子节点存储关键字和数据,而B+的非叶子节点只存储关键字。 2. B的叶子节点存储数据,而B+的叶子节点通过链表连接,并且存储所有的数据。 3. B适用于外存储设备,B+适用于数据库索引等场景。 4. B和B+的查找、插入和删除操作的时间复杂度都是O(log n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值