Java数据结构与算法11——B树

1.B树是什么

B树(即是B-tree,B是Balanced,平衡的意思),是一种平衡的多路搜索树,主要用于磁盘等外部存储的一种数据结构,例如用于文件索引。

2.回忆磁盘存取数据的知识

1.磁盘存取数据的基本过程
(1)根据柱面号使磁头移动到所需要的柱面上,这一过程被称为定位或查找。
(2)根据盘面号来确定指定盘面上的磁道
(3)盘面确定以后,盘片开始旋转,将指定块号的磁道段移动至磁头下

2.磁盘读取数据是以块(block)为基本单位的,因此应尽量将相关信息存放在同一盘块,同一磁道中,以便在读/写信息时尽量减少磁头来回移动的次数,避免过多的查找时间。

3.在大量数据存储在外存磁盘中,如何高效地查找磁盘中的数据,就需要一种合理高效的数据结构了

3.B树的特性

对于一颗m阶(阶指的是子节点的最大值)的B树,有如下特性:

  • 1.根结点要么是叶子,要么至少有两个儿子
  • 2.每个结点最多含有m个孩子(m>=2)
  • 3.除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子
  • 4.所有的叶子结点都出现在同一层上
  • 5.有s个儿子的非叶结点具有 n =s -1 个关键字,即:s= n+ 1
  • 6.每个非叶子节点中包含有n个关键字信息: (n,C0,K1,C1,K2,C2,......,Kn,Cn)。其中:
    (1) Ki (i=1...n)为关键字,且关键字按顺序升序排序K(i-1)< Ki
    (2) Ci为指向子树根的接点,且指针C(i-1)指向子树种所有结点的关键
    字均小于Ki,但都大于K(i-1)
    (3)关键字的个数n必须满足: [ceil(m / 2)-1]<= n <= m-1

4.B树的高度

B树的高度就是B树不包含叶节点的层数。由于磁盘存取时的I/O次数,与B树的高度成正比,高度越小,那么I/O次数也就越小,因此理解如何计算B树的高度是很有必要的。设若B树总共包含N个关键字,则此树的叶子节点可以有N+1个,而所有的叶子结点都在第K层,可以得出:

  • 1.因为根至少有两个孩子,因此第2层至少有两个结点
  • 2.除根和叶子外,其它结点至少有ceil(m/2)个孩子
  • 3.因此在第3层至少有2* ceil(m/2)个结点
  • 4.在第4层至少有2*(ceil(m/2)^2)个结点
  • 5.在第K层至少有2*(ceil(m/2)^(K-2))个结点,于是有:N+1≥2 * (ceil(m/2)^(K-2)) ,这就可以算出:K≤ log(ceil(m/2)((N+1)/2 )+2
  • 6.由于计算B树高度是不包含叶节点的层数,所以: B树的高度≤ log(ceil(m/2)((N+1)/2 )+1

5.B树的搜索、添加、删除节点的算法,并代码示例

5.1 搜索

跟2-3-4树的搜索一样,从根开始查找,判断要搜索的数据处于哪个区间,找到相应的子节点,判断是否匹配,否则重复这些动作。

5.2 插入

插入的时候,会有几种情况:

  • 1.插入到未满的叶节点里面,直接插入数据即可,顶多会引起同一节点内数据项的移动,以保持数据项的顺序

  • 2.插入到未满的子节点里面,子节点的编号就要发生变化,以此来保证树的结构

  • 3.插入到已满的节点中,这就需要做节点分裂,算法如下:
    step1.创建一个空节点,放置到分裂节点的右边
    step2.将一半较大的数据项移动到新节点,中间数据项移动到父节点,一半较小的数据项不动
    step3.重新设置一半较大的数据项和中间数据项的父子节点关系

  • 4.插入到已满的根节点中,这就需要做根节点分裂,算法如下:
    step1.创建一个空节点,作为分裂节点的父节点
    step2.再创建一个空节点,作为分裂节点的兄弟节点
    step3.将一半较大的数据项移动到新的兄弟节点中,中间数据项移动到新的父节点,将一半较小的数据项不动
    step4.重新设置一半较大的数据项和中间数据项的父子节点关系

5.3 删除

1:若删除结点为非叶结点,且被删关键字为该结点中第i个关键字key[i],则可从 C[i]所指的子树中找出最小关键字Y,代替key[i]的位置,然后在叶结点中删去 Y。这样一来,就把在非叶结点删除关键字k的问题就变成了删除叶子结点中的关键字的问题了。

2:要删除的关键字在叶子节点上的情况:先把这个关键字删除掉,然后再调整

3:调整情况:

  • 1)如果被删关键字所在结点的原关键字个数n≥ceil(m/2),说明删去该关键字后该结点仍满足B树的定义,直接删除,不做调整
  • 2)如果被删关键字所在结点的关键字个数n=ceil(m/2)-1,说明删去该关键字后该结点将不满足B树的定义,需要调整,过程为:如果其左右兄弟结点中有“多余”的关键字,即与该结点相邻的右(左)兄弟结点中的关键字数目大于 ceil(m/2)。则可将右(左)兄弟结点中最小(大)关键字上移至父结点,而将父结点中小(大)于该上移关键字的关键字下移至被删关键字所在结点中
  • 3)如果左右兄弟结点中没有“多余”的关键字,需把要删除关键字的结点与其左(或右)兄弟结点以及父结点中分割二者的关键字合并成一个结点,即在删除关键字后,该结点中剩余的关键字,加上父结点中的关键字Ki一起,合并到Ci所指的兄弟结点中去。如果因此使父结点中关键字个数小于ceil(m/2),则对此父结点做同样处理。以致于可能直到对根结点做这样的处理而使整个树减少一层。

6.了解B+树,B+树和B树的差异,B+树的优势

B+树是一种B树的变形树,在实现文件索引方面比B树更好。

6.1 B+树和B树的特性差异

1.有n棵子树的结点中含有n个关键码

2.所有的叶子结点中包含了全部关键码的信息,及指向含有这些关键码记录的指针,且叶子结点本身依关键码的大小自小而大的顺序链接

3.所有的非终端结点可以看成是索引部分,结点中仅含有其子结点中最大(或最小)关键码

4.叶结点中存放的是对实际数据对象的索引。

5.在B+树中有两个头指针:一个指向B+树的根结点,一个指向关键码最小的叶结点。因此可以对B+树进行两种查找运算:一种是从最小关键字起顺序查找,另一种是从根节点开始,进行随机查找。

6.2 B+树的优势

B+树比B 树更适合实际应用中的文件索引和数据库索引,主要在于:

  1. B+树的磁盘读写代价更低
    B+树的非叶结点并没有指向关键字具体信息的指针,比B树更小。如果把所有同一非叶结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字更多,一次可读入内存中的关键字也就更多,从而降低了I/O读写次数

  2. B+树的查询效率更加稳定
    由于非叶结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找都是一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

  3. B+树支持基于范围的查询
    B+树只要遍历叶子节点就可以实现整棵树的遍历,可以很容易的支持范围查询,而B树不支持这样的操作(或者说效率太低),B+树比B树更适合做数据库的索引的数据结构。

参考

  • 1)Java数据结构和算法精讲版

你可能感兴趣的:(Java数据结构与算法11——B树)