数据结构——B-tree(多路搜索树)

###一、前言
B-tree树(多路搜索树,非二叉树),B即Balanced,平衡的意思,有别于二叉查找树(Binary Search Tree),在国内有经常将两者都写作B-树的情形,这其实是非常容易混淆的直译,因为这两种树有非常大的差别,不是同一种数据结构。所以,希望在提到B-tree树时,可以加上多路搜索树的全程,或者读成Balanced Tree以明确区分。还有如果读成了B减树,那可真就丢人了
B-tree这个数据结构一般用于数据库的索引,综合效率较高。比如MySql的索引采用的就是B+树,是B-tree的变体,所以接下来我们先了解B-tree的原理。
###二、数据库索引
树结构的查询效率高,并且可以保持有序,这使得数据库索引使用非常便利。但是既然使用树结构,二叉搜索树的查询时间复杂度是O(log(n)),从算法逻辑上来讲,无论查找速度还是比较次数都是最小的,那为什么数据库索引没有采用二叉搜索树呢?因为在实际情况下,我们不得不考虑另外一个现实问题,磁盘IO,因为数据库的索引通常十分庞大,需要以文件形式存储,而磁盘IO的存取次数就是评价一个数据库索引优劣的关键性指标。
因为索引的加载不可能一次全部加载进内存,磁盘读取每次读取的长度为一个磁盘页的长度,所以数据库系统会将一个节点的大小设为等于一页,这样保证了数据库每个节点只需要一次IO就可以完全加载。每次新建节点,直接申请一个页的空间,计算机存储分配是按页对齐的,这样在物理上也保证了一个节点对应一页,保证一个节点只需要一次IO。在B-tree中m值一般会设的比较大,让树的高度降低,有利于一次完整载入。
树的查找是由树的高度决定的,所以在二叉查找树中,最坏的情况下,磁盘的IO次数等于索引树的高度,而二叉查找树的性质决定了,大数据量的情况下树的高度必然会很高,所以为了减少磁盘IO次数,我们需要将瘦高的树变得矮胖,这也是B-tree的特征之一。
###三、B-tree
B-tree是一种多路平衡查找树,它的每一个节点最多包含m个孩子,m被称为B-tree的阶。数据库索引树中,m的大小取决于磁盘页的大小。一个m阶的B-tree具有如下几个特征:
1.根节点至少有两个孩子
2.每个中间节点都包含k-1个元素和k个孩子,其中m/2<= k <=m
3.每一个叶子节点都包含k-1个元素,其中m/2<= k <=m
4.所有的叶子节点都位于同一层
5.每个节点中的元素从小到大排列,节点中当k-1个元素正好是k个孩子包含的元素的值域分划
这么一条条的规则看起来很生硬,我们以一个3阶B-tree的例子来看
数据结构——B-tree(多路搜索树)_第1张图片
在这张图中,重点看下(5,9)节点,孩子节点有有两个元素5和9,又有三个孩子4,(6,8),13。其中4小于5,(6,8)在(5,9)之间,13大于(5,9)。正好符合上面的几条特征。
我们再来演示下查询的过程,比如说查询元素6。
数据结构——B-tree(多路搜索树)_第2张图片
如图:第一次拿6和12比较,然后从左分支,6再和(5,9)比较,走中间分支,然后6再和(6,8)比较,找到所要查找的元素。在这个过程中,随着元素的增多,实际情况下内存中比较次数可能很多,但是内存的比较时间与磁盘IO消耗相比几乎可以忽略不计。
接下来我们再演示下B-tree添加和删除的情况,因为B-tree之所以叫Balanced tree,那是因为它时刻保持自平衡,所以在插入节点的过程非常复杂,而且需要分多种情况来分析,这里我们只举一个典型的例子来表示出B-tree的特性,从而更方便大家理解它的理念,更多的细节还希望大家在运用的过程中去学习理解。比如我们插入一个节点7,自顶向下查找发现7的位置在(6,8)之间:
数据结构——B-tree(多路搜索树)_第3张图片
节点(6,8)已经是两元素节点,无法在增加。父亲节点(5,9)也是两元素节点,也无法再增加,根节点12是单元素节点,可以升级为两元素节点。升级后,需要拆分(5,9)节点为单元素节点,同时拆分(6,8)为单元素节点,结果如图:
数据结构——B-tree(多路搜索树)_第4张图片
插入一个元素,使得整个树几乎变了样子,但这也是B-tree自平衡的特点。
我们再来看下删除元素的例子,比如删除14。
删除14后,节点15只有一个孩子,不符合B-tree的规范,因此在15,16,18中找出中位数16,使其取代节点15,而15左下移成为孩子,如图:
数据结构——B-tree(多路搜索树)_第5张图片
###四、结语
B-tree主要用在文件系统以及部分数据库索引,比如MongoDB,而MySql使用的是B-tree的变种B+树。上面所举的例子比较简单,但是原理都是通用的,方便大家理解,更深层的东西希望能在今后的学习和工作中领会。

你可能感兴趣的:(算法)