Contents
  1. 1. 前言
  2. 2. 来源
  3. 3. 什么是B-Tree
  4. 4. B-Tree定义
  5. 5. B树结构特性
  6. 6. B树类型和节点定义
  7. 7. 文件查找过程
  8. 8. B+-Tree
  9. 9. B*-Tree
    1. 9.0.0.1. 7.总结
  • 10. 总结
  • 前言

    动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树(Red-Black Tree ),B-tree/B+-tree/ B*-tree (B~Tree)。前三者是典型的二叉查找树结构,其查找的时间复杂度O(log2N)与树的深度相关,那么降低树的深度自然会提高查找效率。

    来源

    但是咱们有面对这样一个实际问题:就是大规模数据存储中,实现索引查询这样一个实际背景下,树节点存储的元素数量是有限的(如果元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下,因此我们该想办法降低树的深度,从而减少磁盘查找存取的次数。一个基本的想法就是:采用多叉树结构(由于树节点元素数量是有限的,自然该节点的子树数量也就是有限的)。
    这样我们就提出了一个新的查找树结构——平衡多路查找树,即B-tree(B-tree树即B树*,B即Balanced,平衡的意思),这棵神奇的树是在Rudolf Bayer, Edward M. McCreight(1970)写的一篇论文《Organization and Maintenance of Large Ordered Indices》中首次提出的。
    后面我们会看到,B树的各种操作能使B树保持较低的高度,从而有效避免磁盘过于频繁的查找存取操作,达到有效提高查找效率的目的。然在开始介绍B~tree之前,先了解下相关的硬件知识,才能很好的了解为什么需要B-tree这种外存数据结构。

    什么是B-Tree

    我们知道,B 树是为了磁盘或其它存储设备而设计的一种多叉(下面你会看到,相对于二叉,B树每个内结点有多个分支,即多叉)平衡查找树。与之前介绍的红黑树很相似,但在降低磁盘I/0操作方面要更好一些。许多数据库系统都一般使用B树或者B树的各种变形结构,如下文即将要介绍的B+树,B*树来存储信息。

    B树与红黑树最大的不同在于,B树的结点可以有许多子女,从几个到几千个。不过B树与红黑树一样,一棵含n个结点的B树的高度也为O(lgn),但可能比一棵红黑树的高度小许多,因为它的分支因子比较大。所以,B树可以在O(logn)时间内,实现各种如插入(insert),删除(delete)等动态集合操作。

    如下图所示,即是一棵B树,一棵关键字为英语中辅音字母的B树,现在要从树中查找字母R(包含n[x]个关键字的内结点x,x有n[x]+1个子女(也就是说,一个内结点x若含有n[x]个关键字,那么x将含有n[x]+1个子女)。所有的叶结点都处于相同的深度,带阴影的结点为查找字母R时要检查的结点):

    相信,从上图你能轻易的看到,一个内结点x若含有n[x]个关键字,那么x将含有n[x]+1个子女。如含有2个关键字D H的内结点有3个子女,而含有3个关键字Q T X的内结点有4个子女。

    B-Tree定义

    树又叫平衡多路查找树。一棵m阶的B 树的特性如下:

    1. 树中每个结点最多含有m个孩子(m>=2);
    2. 除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数);
    3. 根结点至少有2个孩子(除非B树只包含一个结点:根结点);
    4. 所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息(可以看做是外部结点或查询失败的结点,指向这些结点的指针都为null);(注:叶子节点只是没有孩子和指向孩子的指针,这些节点也存在,也有元素。类似红黑树中,每一个NULL指针即当做叶子结点,只是没画出来而已)。
    5. 每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,……,Kn,Pn)。其中:
      a) Ki (i=1…n)为关键字,且关键字按顺序升序排序K(i-1)< Ki。
      b) Pi为指向子树根的结点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。
      c) 关键字的个数n必须满足: [ceil(m / 2)-1]<= n <= m-1。比如有j个孩子的非叶结点恰好有j-1个关键码。

    注:切勿简单的认为一棵m阶的B树是m叉树,虽然存在四叉树八叉树KD树,及vp/R树/R*树/R+树/X树/M树/线段树/希尔伯特R树/优先R树等空间划分树,但与B树完全不等同)

    B树中的每个结点根据实际情况可以包含大量的关键字信息和分支(当然是不能超过磁盘块的大小,根据磁盘驱动(disk drives)的不同,一般块的大小在1k~4k左右);这样树的深度降低了,这就意味着查找一个元素只要很少结点从外存磁盘中读入内存,很快访问到要查找的数据。

    B树结构特性

    一棵m阶B-树,或为空树,或为满足下列特性的m叉树:(m≥3)

    (1)根结点只有1个,关键字字数的范围[1,m-1],分支数量范围[2,m];

    (2)除根以外的非叶结点,每个结点包含分支数范围[[m/2],m],即关键字字数的范围是[[m/2]-1,m-1],其中[m/2]表示取大于m/2的最小整数;

    (3)非叶结点是由叶结点分裂而来的,所以叶结点关键字个数也满足[[m/2]-1,m-1];

    (4)所有的非终端结点包含信息:(n,P0,K1,P1,K2,P2,……,Kn,Pn),

    其中Ki为关键字,Pi为指向子树根结点的指针,并且Pi-1所指子树中的关键字均小于Ki,而Pi所指的关键字均大于Ki(i=1,2,……,n),n+1表示B-树的阶,n表示关键字个数,即[ceil(m / 2)-1]<= n <= m-1;
    

    (5)所有叶子结点都在同一层,并且指针域为空,具有如下性质:

      根据B-树定义,第一层为根有一个结点,至少两个分支,第二层至少2个结点,i≥3时,每一层至少有2乘以([m/2])的i-2次方个结点([m/2]表示取大于m/2的最小整数)。若m阶树中共有N个结点,那么可以推导出N必然满足N≥2*(([m/2])的h-1次方)-1 (h≥1),因此若查找成功,则高度h≤1+logm/2/2,h也是磁盘访问次数(h≥1),保证了查找算法的高效率。

    B树类型和节点定义


    1
    2
    3
    4
    5
    6
    7
    8
    9
    #define MAXM 10 /*定义B-树的最大的阶数*/
    typedef int KeyType; /*KeyType为关键字类型*/
    typedef struct BTNode /*B-树结点类型定义*/
    {
    int keynum; /*结点当前拥有的关键字的个数*/
    KeyType key[MAXM]; /*key[1..keynum]存放关键字,key[0]不用*/
    struct BTNode *parent; /*双亲结点指针*/
    struct BTNode *ptr[MAXM]; /*孩子结点指针数组ptr[0..keynum]*/
    }BTTree;

    文件查找过程

    为了简单,这里用少量数据构造一棵3叉树的形式,实际应用中的B树结点中关键字很多的。上面的图中比如根结点,其中17表示一个磁盘文件的文件名;小红方块表示这个17文件内容在硬盘中的存储位置;p1表示指向17左子树的指针。

    其结构可以简单定义为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typedef struct {
    /*文件数*/
    int file_num;
    /*文件名(key)*/
    char * file_name[max_file_num];
    /*指向子节点的指针*/
    BTNode * BTptr[max_file_num+1];
    /*文件在硬盘中的存储位置*/
    FILE_HARD_ADDR offset[max_file_num];
    }BTNode;

    假如每个盘块可以正好存放一个B树的结点(正好存放2个文件名)。那么一个BTNODE结点就代表一个盘块,而子树指针就是存放另外一个盘块的地址。

    B+-Tree

    一棵m阶的B+树和m阶的B树的异同点在于:

    1. 有n棵子树的结点中含有n-1 个关键字; (与B 树n棵子树有n-1个关键字 保持一致,参照:http://en.wikipedia.org/wiki/B%2B_tree#Overview,而下面B+树的图可能有问题,请读者注意)
    2. 所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息)
    3. 所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息)

    B*-Tree

    7.总结

    通过以上介绍,大致将B树,B+树,B*树总结如下:

    • B树:有序数组+平衡多叉树;
    • B+树:有序数组链表+平衡多叉树;
    • B*树:一棵丰满的B+树。

    顺便说一句,无论是B树,还是B+树、b树,由于根或者树的上面几层被反复查询,所以这几块可以存在内存中,换言之,B树、B+树、B树的根结点和部分顶层数据在内存中,大部分下层数据在磁盘上。

    总结

    通过以上介绍,大致将B树,B+树,B*树总结如下:

    • B树:有序数组+平衡多叉树;
    • B+树:有序数组链表+平衡多叉树;
    • B*树:一棵丰满的B+树。

    顺便说一句,无论是B树,还是B+树、b树,由于根或者树的上面几层被反复查询,所以这几块可以存在内存中,换言之,B树、B+树、B树的根结点和部分顶层数据在内存中,大部分下层数据在磁盘上。

    Contents
    1. 1. 前言
    2. 2. 来源
    3. 3. 什么是B-Tree
    4. 4. B-Tree定义
    5. 5. B树结构特性
    6. 6. B树类型和节点定义
    7. 7. 文件查找过程
    8. 8. B+-Tree
    9. 9. B*-Tree
      1. 9.0.0.1. 7.总结
  • 10. 总结