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

0x00 前言

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

0x01 定义

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

B+树的定义如下:

每个节点node有下面的属性: n个关键字key[1],key[2], … ,key[n],以非降序存放,使得key[1]≤key[2]≤…≤key[n];
isRoot,一个布尔值,如果node是根节点,则为TRUE;否则为FALSE;
isLeaf,一个布尔值,如果node是叶子节点,则为TRUE;否则为FALSE;
Node*类型的parent指针,指向该节点的父节点

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

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

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

结合以上的具体定义,下面这张图更加详细的描述了一棵具体的B+树

0x02 注意点

在B+树的学习与实现过程中,也遇到不少的疑惑之处,现记录如下,持续更新:
内部节点并不存储真正的信息,而是保存其叶子节点的最小值作为索引。每次插入删除都进行更新(此时用到parent指针),保持最新状态。
关于所有叶子节点都处于同一深度是如何实现的?这与B+树具体的插入和删除算法有关。简单解释一下插入时的情况,根据插入值的大小,逐步向下直到对应的叶子节点。如果叶子节点关键字个数小于2t,则直接插入值或者更新卫星数据;如果插入之前叶子节点已经满了,则分裂该叶子节点成两半,并把中间值提上到父节点的关键字中,如果这导致父节点满了的话,则把该父节点分裂,如此递归向上。所以树高是一层层的增加的,叶子节点永远都在同一深度。下面是我实现的B+树中的插入代码的片段:
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);
}
}

0x03 结语

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

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

参考文献
[1].《算法导论》原书第3版中文版
[2]. 维基百科B+树条目
[3]. 很详细的一篇B树、B+树、R树的博客 
[4]. 数据库实现的扼要说明
 

参考

SQL学习笔记之B+树的几点总结的更多相关文章

  1. SQL学习笔记之B+树

    0x00 概述 要描述清楚B+树,得先了解二叉查找数,平衡二叉树. 0x01 二叉查找树 任意节点,它的左子树如果不为空,那么左子树上所有节点的值都小于根节点的值:任意节点,他的右子树如果不为空,那么 ...

  2. ORALCE PL/SQL学习笔记

    ORALCE  PL/SQL学习笔记 详情见自己电脑的备份数据资料

  3. 【学习笔记】线段树—扫描线补充 (IC_QQQ)

    [学习笔记]线段树-扫描线补充 (IC_QQQ) (感谢 \(IC\)_\(QQQ\) 大佬授以本内容的著作权.此人超然于世外,仅有 \(Luogu\) 账号 尚可膜拜) [学习笔记]线段树详解(全) ...

  4. Oracle之PL/SQL学习笔记

    自己在学习Oracle是做的笔记及实验代码记录,内容挺全的,也挺详细,发篇博文分享给需要的朋友,共有1w多字的学习笔记吧.是以前做的,一直在压箱底,今天拿出来整理了一下,给大家分享,有不足之处还望大家 ...

  5. SQL学习笔记

    SQL(Structured Query Language)学习笔记 [TOC] Terminal登录数据库 1.登录mysql -u root -p ; 2.显示所有数据库show database ...

  6. SQL学习笔记之MySQL索引知识点

    0x00 概述 之前写过一篇Mysql B+树学习,简单的介绍了B+数以及MySql使用B+树的原因, 有了这些基础知识点,对MySql索引的类型以及索引使用的一些技巧,就比较容易理解了. 0x01 ...

  7. [SQL学习笔记][用exists代替全称量词 ]

    学习sql的必经问题. 学生表student (id学号 Sname姓名 Sdept所在系) 课程表Course (crscode课程号 name课程名) 学生选课表transcript (studi ...

  8. SQL学习笔记——SQL初入门,Ubuntu下MySQL的安装

          刚开始接触sql,于是准备在Ubuntu下学习sql,就跟着itercast的sql教程开始入门了. 下面只是我个人的记录,高手请绕道: 一. 在安装之前,我们可以用下面这个命令通过开放端 ...

  9. PL\SQL学习笔记

    注释 单行--多行 一.declare一般用于做变量的申明.begin 程序体开始执行  end; 程序体结束exception .. dbms_output.put_line('绝对值'||v_ab ...

随机推荐

  1. sql语法:从一个表update到另外一个表

    sql语法:从一个表update到另外一个表 一. update a set a.name=b.name1 from a,b where a.id=b.id 二. update table1 set ...

  2. HDU1536 S-Nim

    S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  3. Struts入门(三)深入Struts用法讲解

    访问Servlet API Action搜索顺序 动态方法调用 指定多个配置文件 默认Action Struts 后缀 接收参数 处理结果类型 1.访问Servlet API 首先我们了解什么是Ser ...

  4. Storm 在ZK 上的目录图

    这是Zk 的可视化工具 看到的Storm 目录结构 ,这时候没有提交任何的任务给这个集群, 其实这时候我只是启动了 nimbus 还没有启动Supervisors  ,所有你 看懂的Superviso ...

  5. Ubuntu 14.04 安装jdk,tomcat

     分类: 碎知识(8)  版权声明:本文为博主原创文章,未经博主允许不得转载. 写在前面: 装的时候,参考了许多网上的资料,有很多人写的有些简单了,人家那边版本稍微一更新,像我这样的小白就找不到东南西 ...

  6. xpath scrapy shell

    w from scrapy.spider import Spider from scrapy.crawler import CrawlerProcess import pymysql conn = p ...

  7. 购物车删除商品,总价变化 innerHTML = ''并没有删除节点,内容仍存在

    w元素的上的下. function deleteLi(tmpId) { //document.getElementById(tmpId).innerHTML = ''; var wdel = docu ...

  8. 如何查看电脑最大支持多少GB内存

    第一种方法: 1.打开“开始”菜单,点击“运行”按钮,也可以直接使用[Win + R]组合快捷键打开, 在弹出来的窗口输入“CMD”,然后确定或者按下回车键 2.在命令窗口输入“wmic memphy ...

  9. Win10图标显示不正常解决办法

    当缓存文件出现问题时,就会引发系统图标显示不正常: 1.由于图标缓存文件是隐藏文件,我们需要在资源管理器中将设置改为“显示所有文件”. 2.同时按下快捷键 Win+R,在打开的运行窗口中输入 %loc ...

  10. 转载(web app变革之rem)

    rem这是个低调的css单位,近一两年开始崭露头角,有许多同学对rem的评价不一,有的在尝试使用,有的在使用过程中遇到坑就弃用了.但是我对rem综合评价是用来做web app它绝对是最合适的人选之一. ...