关于B树的阶

B树的阶(英语对应order)定义是不统一的: 
Unfortunately, the literature on B-trees is not uniform in its terminology (Folk & Zoellick 1992, p. 362). 
Bayer & McCreight (1972), Comer (1979), and others define the order of B-tree as the minimum number of keys in a non-root node. 
Folk & Zoellick (1992) points out that terminology is ambiguous because the maximum number of keys is not clear. An order 3 B-tree might hold a maximum of 6 keys or a maximum of 7 keys. 
Knuth (1998, p. 483) avoids the problem by defining the order to be maximum number of children (which is one more than the maximum number of keys).

国内的数据结构教材一般是按照Knuth定义,即“阶”定义为一个节点的子节点数目的最大值。

对于一棵m阶B-tree,每个结点至多可以拥有m个子结点。各结点的关键字和可以拥有的子结点数都有限制,规定m阶B-tree中,根结点至少有2个子结点,除非根结点为叶子节点,相应的,根结点中关键字的个数为1~m-1,比节点数目少一个;非根结点至少有[m/2]([],向上取整)个子结点,相应的,关键字个数为[m/2]-1~m-1。

上面这段引用自 https://darrenzhu.iteye.com/blog/2050087

以下转自 https://www.cnblogs.com/xiaoxi/p/6868087.html

一、零铺垫

在介绍B树之前,先来看另一棵神奇的树——二叉排序树(Binary Sort Tree),首先它是一棵树,“二叉”这个描述已经很明显了,就是树上的一根树枝开两个叉,于是递归下来就是二叉树了(下图所示),而这棵树上的节点是已经排好序的,具体的排序规则如下:

  • 若左子树不空,则左子树上所有节点的值均小于它的根节点的值
  • 若右子树不空,则右子树上所有节点的值均大于它的根节点的值
  • 它的左、右子树也分别为二叉排序数(递归定义)

从图中可以看出,二叉排序树组织数据时,用于查找是比较方便的,因为每次经过一次节点时,最多可以减少一半的可能,不过极端情况会出现所有节点都位于同一侧,直观上看就是一条直线,那么这种查询的效率就比较低了,因此需要对二叉树左右子树的高度进行平衡化处理,于是就有了平衡二叉树(Balenced Binary Tree)。

所谓“平衡”,说的是这棵树的各个分支的高度是均匀的,它的左子树和右子树的高度之差绝对值小于1,这样就不会出现一条支路特别长的情况。于是,在这样的平衡树中进行查找时,总共比较节点的次数不超过树的高度,这就确保了查询的效率(时间复杂度为O(logn))。

二、B树的起源

B树,最早是由德国计算机科学家Rudolf Bayer等人于1972年在论文 《Organization and Maintenance of Large Ordered Indexes》提出的,不过我去看了看原文,发现作者也没有解释为什么就叫B-trees了,所以把B树的B,简单地解释为Balanced或者Binary都不是特别严谨,也许作者就是取其名字Bayer的首字母命名的也说不定啊……

三、B树长啥样

还是直接看图比较清楚,图中所示,B树事实上是一种平衡的多叉查找树,也就是说最多可以开m个叉(m>=2),我们称之为m阶b树,为了体现本博客的良心之处,不同于其他地方都能看到2阶B树,这里特意画了一棵5阶B树 。

总的来说,m阶B树满足以下条件:

  • 每个节点至多可以拥有m棵子树
  • 根节点,只有至少有2个节点(要么极端情况,就是一棵树就一个根节点,单细胞生物,即是根,也是叶,也是树)。
  • 非根非叶的节点至少有的Ceil(m/2)个子树(Ceil表示向上取整,图中5阶B树,每个节点至少有3个子树,也就是至少有3个叉)。
  • 非叶节点中的信息包括[n,A0,K1,A1,K2,A2,…,Kn,An],,其中n表示该节点中保存的关键字个数,K为关键字且Ki<Ki+1,A为指向子树根节点的指针。
  • 从根到叶子的每一条路径都有相同的长度,也就是说,叶子节在相同的层,并且这些节点不带信息,实际上这些节点就表示找不到指定的值,也就是指向这些节点的指针为空。

B树的查询过程和二叉排序树比较类似,从根节点依次比较每个结点,因为每个节点中的关键字和左右子树都是有序的,所以只要比较节点中的关键字,或者沿着指针就能很快地找到指定的关键字,如果查找失败,则会返回叶子节点,即空指针。

例如查询图中字母表中的K

  1. 从根节点P开始,K的位置在P之前,进入左侧指针
  2. 左子树中,依次比较C、F、J、M,发现K在J和M之间
  3. 沿着J和M之间的指针,继续访问子树,并依次进行比较,发现第一个关键字K即为指定查找的值

四、Plus版——B+树

作为B树的加强版,B+树与B树的差异在于

  • 有n棵子树的节点含有n个关键字(也有认为是n-1个关键字)
  • 所有的叶子节点包含了全部的关键字,及指向含这些关键字记录的指针,且叶子节点本身根据关键字自小而大顺序连接
  • 非叶子节点可以看成索引部分,节点中仅含有其子树(根节点)中的最大(或最小)关键字

B+树的查找过程,与B树类似,只不过查找时,如果在非叶子节点上的关键字等于给定值,并不终止,而是继续沿着指针直到叶子节点位置。因此在B+树,不管查找成功与否,每次查找都是走了一条从根到叶子节点的路径。

五、MySQL是如何使用B树的

说明:事实上,在MySQL数据库中,诸多存储引擎使用的是B+树,即便其名字看上去是BTREE。

1、innodb的索引机制

先以innodb存储引擎为例,说明innodb引擎是如何利用B+树建立索引的。首先创建一张表:zodiac,并插入一些数据

CREATE TABLE `zodiac` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `index_name` (`name`)
); insert zodiac(id,name) values(1,'鼠'); &nbsp;
insert zodiac(id,name) values(2,'牛'); &nbsp;
insert zodiac(id,name) values(3,'虎'); &nbsp;
insert zodiac(id,name) values(4,'兔'); &nbsp;
insert zodiac(id,name) values(5,'龙'); &nbsp;
insert zodiac(id,name) values(6,'蛇'); &nbsp;
insert zodiac(id,name) values(7,'马'); &nbsp;
insert zodiac(id,name) values(8,'羊'); &nbsp;
insert zodiac(id,name) values(9,'猴');
insert zodiac(id,name) values(10,'鸡'); &nbsp;
insert zodiac(id,name) values(11,'狗'); &nbsp;
insert zodiac(id,name) values(12,'猪');

对于innodb来说,只有一个数据文件,这个数据文件本身就是用B+树形式组织B+树每个节点的关键字就是表的主键,因此innodb的数据文件本身就是主索引文件,如下图所示,主索引中的叶子页(leaf page)包含了数据记录,但非叶子节点只包含了主键,术语“聚簇”表示数据行和相邻的键值紧凑地存储在一起,因此这种索引被称为聚簇索引,或聚集索引。

这种索引方式,可以提高数据访问的速度,因为索引和数据是保存在同一棵B树之中,从聚簇索引中获取数据通常比在非聚簇索引中要来得快。

所以可以说,innodb的数据文件是依靠主键组织起来的,这也就是为什么innodb引擎下创建的表,必须指定主键的原因,如果没有显式指定主键,innodb引擎仍然会对该表隐式地定义一个主键作为聚簇索引。

同样innodb的辅助索引,如下图所示,假设这些字符是按照生肖的顺序排列的(其实我也不知道具体怎么实现,不要在意这些细节,就是举个例子),其叶子节点中也包含了记录的主键,因此innodb引擎在查询辅助索引的时候会查询两次,首先通过辅助索引得到主键值,然后再查询主索引,略微有点啰嗦。。。

2、MyISAM的索引机制

MyISAM引擎同样也使用B+树组织索引,如下图所示,假设我们的数据不是按照之前的顺序插入的,而是按照图中的是顺序插入表,可以看到MyISAM引擎下,B+树叶子节点中包含的是数据记录的地址(可以简单理解为“行号”),而MyISAM的辅助索引在结构上和主索引没有本质的区别,同样其叶子节点也包含了数据记录的地址,稍微不同的是辅助索引的关键字是允许重复。

六、简单对比

1、Innodb辅助索引的叶子节点存储的不是地址,而是主键值,这样的策略减少了当出现行移动或者数据页分裂时辅助索引的维护工作,虽然使用主键值当作指针会让辅助索引占用更多空间,但好处是,Innodb在移动行时无需更新辅助索引中的主键值,而MyISAM需要调整其叶子节点中的地址。

2、innodb引擎下,数据记录是保存在B+树的叶子节点(大小相当于磁盘上的页)上,当插入新的数据时,如果主键的值是有序的,它会把每一条记录都存储在上一条记录的后面,但是如果主键使用的是无序的数值,例如UUID,这样在插入数据时Innodb无法简单地把新的数据插入到最后,而是需要为这条数据寻找合适的位置,这就额外增加了工作,这就是innodb引擎写入性能要略差于MyISAM的原因之一。

Innodb和MyISAM索引的抽象图

啊 B树的更多相关文章

  1. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  2. ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  3. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  4. HDU1671——前缀树的一点感触

    题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...

  5. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  6. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  7. bzoj3207--Hash+主席树

    题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...

  8. bzoj1901--树状数组套主席树

    树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...

  9. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  10. jquery-treegrid树状表格的使用(.Net平台)

    上一篇介绍了DataTable,这一篇在DT的基础之上再使用jquery的一款插件:treegrid,官网地址:http://maxazan.github.io/jquery-treegrid/ 一. ...

随机推荐

  1. ELK-filebeat收集日志到Kafka,并转存ES

    https://blog.51cto.com/tryingstuff/2052271 场景需求 在有些不需要安装java环境的服务器如Nginx,php等为主的web 应用可以使用filebeat来对 ...

  2. Intellij IDEA 14中使用MyBatis-generator 自动生成MyBatis代码

    一:项目建立好及其基本的测试好 二:在maven项目的pom.xml 添加mybatis-generator-maven-plugin 插件 <build> <finalName&g ...

  3. iis7设置ftp

    目前是所有网站一个域下.ftp登录后可看到所有网站,目前想ftp一个网站,查看了下服务器,貌似只有serv-u这么个东西,还不能再创建第二个域.不得其解.百度发现两篇文章正好: http://blog ...

  4. JGUI源码:实现简单进度条(19)

    程序效果如下 实现进度条动画主要有两种方法:(1)使用缓动,(2)使用Jquery Animate,本文使用第二种方法,先实现代码,后续进行控件封装 <style> .jgui-proce ...

  5. python学习06

    流控制 和函数 1)流控制 1.条件语句 if elif else  if else 2.循环语句 while for 3.continue 和break continue是跳过本次循环,执行下一次循 ...

  6. [Jetty] Debugging With Eclipse

    There are a number of options available to debug your application in Eclipse. If not done already pr ...

  7. 在Windows Server上安装ASP.NET时失败,提示not enough storage is available to process the command

    今天在部署ASP.NET网站时出现IIS 500.21错误.环境是Windows Server 2012 +IIS8 于是查找解决方案,发现网上的信息都说是需要重装.NET framerwork4.0 ...

  8. VLAN原理解释

    转发至http://network.51cto.com/art/201409/450885.htm 为什么需要VLAN 1. 什么是VLAN? VLAN(Virtual LAN),翻译成中文是“虚拟局 ...

  9. 动态将ASPX生成HTML网页并将网页导出PDF

    1.首先要找到wnvhtmlconvert.dll这个文件,并引入项目中. 2.Server.Execute("pos.aspx?id=" + ids); 执行相应的aspx网页 ...

  10. 前端node.js npm i 报错Unexpected end of JSON input while parsing near

    清缓存 npm cache clean --force 重新安装 npm install