B树

来源:互联网 发布:未来天空摇杆淘宝店 编辑:程序博客网 时间:2024/06/05 03:22

B树是另一种平衡查找树,它与AVL树以及红黑树的区别在于,它的一个节点可以由多个子女,由于B树中每个节点子女比ALV树和红黑树多,因而它的高度要比这种两种树更低,不过数量级仍为O(logn)。

B树中一个节点的关键字将该节点所处理的关键字域划分成了多个子域,如果一个节点有x个关键字,则它有x+1个孩子。下图即为一棵B树:


一、B树的基本性质

B树是一种平衡的多路查找树,一棵B树,或者为空树,或者为满足如下性质的多叉树:

  1. 所有叶子都在同一层上,和红黑树类似,B树中的叶子是空节点,不保存任何信息
  2. 每个节点能包含的关键字的数目有一个上界和下界。假设B树的最小度树为t(t>=2),则
    • 每个非根的节点必须至少有t-1个关键字,有个孩子;如果树非空,则根节点至少包含一个关键字
    • 每个节点至多能包含2t-1个关键字,即每个节点至多有2t个孩子
  3. 所有非叶子节点包含了如下信息:
    • 该节点上的关键字数目num
    • 以非降序排列的关键字序列{key1.key2,...,keynum},key1<=key2<=,...,<=keynum
    • 指向num+1个子树的指针
B树的一个变形是B+树,在B+树中所有的信息都保存在叶子中,内节点只包含关键字和指针信息。

B树的高度h满足:h<= logt((n+1)/2),因此它仍未O(logn)

二、B树的查找

根据B树的概念可知,在其上查找和AVL树以及红黑树上的查找是类似的,唯一的区别在于B树中在每个节点上可能需要和它所包含的多个关键字左比较而不是一个,不过由于这些关键字是排序的,因而比较只需要顺序进行即可,因此B树的查找性能也很好,时间复杂度为O(tlogtn)

三、B树的插入

类似于AVL树和红黑树的插入,我们先将插入分为两步,第一步找到插入点,第二部再对树进行调整以满足B树的性质要求。从B树的性质我们可以知道,在插入新的关键字后,由于我们必定以有序的方式插入,因而唯一可能被违背的B树的性质就是对每个节点上关键字数目限制的要求。根据B树的性质,如果插入后,某个节点的关键字数目违背了B树的性质,我们就需要对它进行拆分,使得B树的性质得以保持。
根据B树的性质,一个节点至多包含2t-1个关键字,至少包含t-1个性质,如果插入新的关键字后,一个节点违背了B树的性质,则它包含2t个关键字,因而拆分节点也很简单,只需要将这一个节点拆分为两个节点即可,但是为了将新节点和B树中的其它节点关联起来,我们还必须从新得到的两个节点中提取一个关键字,并把它插入到原节点的父节点中,该关键则将成为父节点分割这两个新节点的关键字。下图即为一个示例(假设t为2):

从上图可以看到,分割节点很简单,做法是:
  1. 将待分割节点的关键字分为三个部分:比中间值小的,中间值,比中间值大的
  2. 将中间值上提到其父节点
  3. 比中间值小的部分和比中间值大的部分分别成为父节点的一个子节点
不过需要注意的是这个过程实际上为父节点增加了一个节点,因此父节点可能也需要继续分割,因此我们可能需要递归的进行分割,直到某次分割后B树的性质不被违背。
递归的回溯进行处理当然是可以的,但是结合B树的性质提前进行处理则可以简化处理的逻辑(但是并不能减少分割需要的次数),很显然在插入后需要进行分割的节点必然包含2t-1个关键字,否则增加一个关键字不会违背B树的性质,也就是说需要进行分割的节点必然是包含了最大关键字数目的节点,与其在插入后在回溯中进行分割,不如在查找关键字插入位置时就对查找路径上的每一个包含了最大关键字数目的节点都提前进行分割,这样就不用在插入后再进行回溯分割了。因此B树插入的基本思想是:
  1. 查找关键字插入位置时,对查找路径上的每一个节点,如果它已经包含了最多的关键子数目,则对它进行分割
  2. 找到插入位置后,插入新的关键字即可
从中可以看出,插入的时间复杂度和查找是相同的(因为分割实际上可以在常数时间内结束)。
对于B树,其高度增高的唯一方式就是根节点被分割。

四、B树的删除

B树上的删除比插入稍微复杂些,其基本思想仍是找到要删除的关键字,然后删除它,再对删除后的树进行调整。找到元素并删除的过程很简单,无需赘述,关键是来分析下删除后的调整。
删除需要分如下几种情形:

4.1 被删除关键字的节点包含的关键字数目大于等于t

此种情形最简单,直接删除关键字即可,B树的性质在删除关键字后不会被违背

4.2 被删除关键字的节点包含的关键字数目等于t-1,但是其邻居节点包含了大于等于t个数目的关键字

此种情形如图所示(假设t为2):

其处理思想是:
  1. 上提邻居节点中的最小值(如果是右边的邻居)或者最大值(如果是左边的邻居),并将被上提的关键字从该邻居中删除
  2. 用被上提的关键字替换父节点中原来用于分割这两个子节点的关键字
  3. 将父节点中原来用于分割这两个孩子的关键字插入到被删除关键字的节点中

4.3 被删除关键字的节点包含的关键字数目等于t-1,其邻居节点也都包含t-1个关键字

该情形如下图所示(假设t=3):

其处理思想是:将被删除关键字的节点和其一个邻居以及分割这两个节点的父节点中的关键字合并为一个新的节点,但是这也相当于从父节点中删除了一个元素,因此还需要将父节点看做了被删除了一个关键字的节点进行递归的处理,比如上图中的情形就需要将包含关键字50的节点当做被删除了一个关键字的节点进行新的处理。

原创粉丝点击