平衡多叉树--B-Tree(B树)

  关键词:M阶、B树、分裂、合并

  前言:

    具体讲解之前,有一点,再次强调下:B-树,即为B树。因为B树的原英文名称为B-tree,而国内很多人喜欢把B-tree译作B-树,其实,这是个非常不好的直译,很容易让人产生误解。如人们可能会以为B-树是一种树,而B树又是一种树。而事实上是,B-tree就是指的B树。 (B树 <=> B-树)。引自:https://www.cnblogs.com/yfzhou/p/10290006.html

1、B树定义:

  对于B树,我们一般描述成M(M>2)阶B树(这里的M阶指的是树的所有结点中的子树个数的最大值)。对于B树来说,它必须满足如下的性质:
   性质
  (1)节点的性质:
    • 所有的叶子节点都在同一层;
    • 每个节点由若干个指针和记录组成。其中,每个节点中记录的个数比指针的个数少1个,指针将记录一一隔开。
  (2)指针的性质:
    • 每一个指针指向一个子节点;
    • 每个节点最多有M个指针;
    • 非叶子节点的根结点最少有两个分支;
    • 叶子节点最少包含一个记录和两个空指针,叶节点的指针均为NULL;
    • 非根非叶结点至少有ceil(M/2)个分支;(ceil(M/2)>=3)(分析:当这个值等于2,那么就变成二叉树;当这个值等于1,那么就变成链表。所以这个值必须大于等于3)
    • 对于任意一个节点:ceil(M/2) <= d <= m。 (从上一点可以推导出来)(d:表示每个节点的度)
  (3)记录的性质:
    • 每个记录由[key, data]组成,同时每个记录按key的大小从坐到右非递减排列;
    • 对于节点中任何一个记录,其左边的指针指向的子节点上的所有记录的key值都小于当前记录的,右边指针的都大于当前记录的;
    • 对于任意一个节点:ceil(M/2)-1 <= k_count <= m-1。(k_count:表示每个节点的记录个数)

一棵B树如下:

2、B树的特性总结:

(1)每个节点都存储了[key, data]
(2)任何一个关键字出现且只出现在一个结点中;
(3)搜索有可能在非叶子结点结束;
(4) 由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并;(插入、删除操作时需要解决的问题)
(5)B树同红黑树一样都是自平衡的树。

3、B树的搜索:

(1)搜索流程

①从根结点开始,对结点内的关键字按照顺序继续进行等值判断;

②如果命中则结束,当前这个关键字对应的记录便是要查找的;

③如果没有命中,则进入查询关键字所属范围的儿子节点内,重复①的操作,直到所对应的儿子指针为空,或已经是叶子结点。此时则说明树中不存在这个关键字。

(2)B-Tree上查找算法的伪代码如下:

1. BTree_Search(node, key) {
2.     if(node == null) return null;
3.     foreach(node.key)
4.     {
5.         if(node.key[i] == key) return node.data[i];
6.         if(node.key[i] > key) return BTree_Search(point[i]->node);
7.     }
8.     return BTree_Search(point[i+1]->node);
9. }
10. data = BTree_Search(root, my_key);

4、B树的插入、删除:

前言 修复方式之分裂、合并、转移:
由于插入、删除数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质。
①分裂:拆分当前节点的中间节记录到上层,与上层的节点的记录进行合并操作;
②合并:将记录与上层节点的记录进行合并;
③转移:需要不断将当前记录与其的相邻下级子节点中的记录进行交换,直到当前记录处于叶子节点中。(如果操作的节点记录不在叶子节点,那么就需要进行转移操作)
 
(1)插入:B树的插入总是在叶子节点上
如果插入新的数据记录到某个节点之后,节点的记录个数大于等于M,那么需要进行分裂操作。
2)删除:
①如果节点不在叶子节点上,那么需要把它替换到叶子节点上。然后对叶子节点执行删除操作;
②如果删除当前节点的某个记录之后,节点的记录个数小于ceil(M/2),那么需要进行合并操作;
③如果合并之后,上级节点记录个数小于等于ceil(M/2),那么此时首先判断当前节点的兄弟节点的记录个数是否在小于ceil(m/2),如果不是,那么取兄弟节点的一个记录与上级节点进行合并。否则,只能从上级节点的上级节点拉取一个记录下来进行合并。
 
注意:
插入、删除的示例详见https://www.cnblogs.com/yfzhou/p/10290006.html
②体情况具体分析。遇到连锁反应(eg:分裂之后有需要分裂),就继续处理呗。

5、B树的节点的存储:

  虽然B-Tree中不同节点存放的key和指针可能数量不一致,但是每个节点的域和上限是一致的,所以在实现中B-Tree往往对每个节点申请同等大小的空间。
 
 
引用: 

猜你喜欢

转载自www.cnblogs.com/axing-articles/p/11442726.html