B树

       首先B树是搜索二叉树的一种拓展,B-Tree 是一种自平衡的树(所有的叶子节点拥有相同的高度)类型的数据结构。但是和其它树比如红黑树,AVL树只有两个孩子:左孩子和右孩子不同,B-Tree 的子节点多余或者等于2两个孩子。因此,有的时候M叉树,因为它可以有M个子节点(M>=2)。如图:

        B树一开始是针对机械磁盘而设计的,因为机械磁盘的磁头跳转消耗的时间比较多,为了减少跳转的次数,所以设计了B-Tree。B树的目标是在O(lgn)时间复杂度内,完成一些动态操作。红黑二叉树的时间复杂度也是O(lgn),所以B树的优势是比红黑树存储更多的节点。所以很多数据库的存储引擎是B树,或者B树的变种B+树,还有B*树,更多细节我们后面慢慢研究。对于各种树最主要的是平衡在这里有一个疑惑:B树和红黑树的动态操作的最坏时间复杂度都是O(lgn),那么二者区别在哪?在于B树能容纳更多的数据,并且B树的高度是可以控制的,而二叉树是不可以的,B树能更加方便得让子节点存放在硬盘。所以B树能减少机械磁盘的磁头跳转的次数,B树更加适合大量数据动态操作(很多数据库使用B+树来实现存储和检索)。

B树的定义 

看了很多定义,觉得《算法导论》给的比较权威:

一棵B树T是具有以下性质的有根树(根为T.root):

1. 每个结点有下面属性:

  • x.n表示当前存储在结点中的关键字个数。
  • x.n个关键字本身x.key_{1}, x.key_{2}, ..., x.key_{n},以非降序存放,即x.key_{1} \leq x.key_{2} \leq ... \leq x.key_{n}
  • x.leaf,一个boolean值,如果x是叶子节点则为true,否则为false。

2. 每个内部结点x还包含x.n+1个指向其孩子的指针 x.c_{1}, x.c_{2}, ... , x.c_{n} 。叶结点没有孩子,所以它们的c_{i}属性没有定义。

3. 关键字x.key_{i} 对存储在各子树中的关键字范围加以分割:如果为任意一个存储在以x.c_{i}为根的子树中的关键字,那么k_{1} \leq x.key_{1} \leq k_{2} \leq x.key_{2} \leq ... \leq x.key_{x.n} \leq k_{x.n+1}

4. 每个叶结点具有相同的深度,即树的高度h。

5. 每个结点所包含的关键字个数有上界和下界。用一个被称为B树的最小度数(minmum degree)的规定整数 t \geqslant 2表示这里的界。

  • 除了根结点以外的每个结点必须至少有 t -1个关键字,因此,除了根结点以外的每个内部结点至少有t个孩子。如果树非空,根结点至少有一个关键字。
  • 每个结点至多可包含2t - 1个关键字。因此,一个内部结点至多可有2个孩子。当一个结点恰好有2t-1个关键字时,称该结点是满的(full)。
     

首先我们先根据上面的特点建模。可能大家并不是很理解,可以做一个构建B-Tree的过程来帮大家理解:

t = 2时的B树是最简单的。每个内部结点有2个、3个孩子,即一棵2-3树。然而在实际中,t的值越大,B树的高度就越小 。 

1.  2.   3.  4.   5.  6.

7. 

通过上面最简单的2-3-4树,大家应该可以大致明白B-Tree的作用。那么我们开始建模。 

public class BTNode<K extends Comparable, V> {

    //每个结点所包含的关键字个数有上界和下界。用一个被称为B树的最小度数(minmum degree)的规定整数 表示这里的界。
    public final static int MIN_DEGREE          =   2;
    //除了根结点以外的每个结点必须至少有 t -1个关键字
    public final static int LOWER_BOUND_KEYNUM  =   MIN_DEGREE - 1;
    //每个结点至多可包含2t - 1个关键字。
    public final static int UPPER_BOUND_KEYNUM  =   (MIN_DEGREE * 2) - 1;

    //x.leaf,一个boolean值,如果x是叶子节点则为true,否则为false。
    protected boolean mIsLeaf;
    //x.n表示当前存储在结点中的关键字个数。
    protected int mCurrentKeyNum;
    //x.n个关键字本身,以非降序存放。
    protected BTKeyValue<K, V> mKeys[];
    //每个内部结点x还包含x.n+1个指向其孩子的指针。叶结点没有孩子,所以它们的属性没有定义。
    protected BTNode mChildren[];

    class BTKeyValue<K extends Comparable, V>
    {
        protected K mKey;
        protected V mValue;

        public BTKeyValue(K key, V value) {
            mKey = key;
            mValue = value;
        }
    }

    ...
    //省略其它的构造方法

}

另外在这里可以得出一个定理:如果n \geq 1, 那么对任意一颗包括个关键字、高度为h、最小度数为t \geq 2的B树T,有

h \leq log_{t} \frac{n+1}{2},这个定理的证明很简单,这里不给了(感兴趣的朋友可以看看《算法导论》),根据这个定理我们也可以知道为什么B-Tree的很多动态操作可以做到o(lgn)复杂度了。

B-Tree的基本操作

搜索B树

在B树众多动态操作中,搜索是最简单的,所以我们从搜索开始讲起。

在实际运用中,B-Tree面对的数据都是非常大量的数据,一般只会把root节点保存在内存中,其它的节点都是存储在磁盘之中。但是这些都不一定,这里实现B-Tree的时候,不会细究这些细节(两种情况:全部节点在内存中,部分节点在内存中)。

    public V search(K key) {
        BTNode<K, V> currentNode = mRoot;
        BTKeyValue<K, V> currentKey;
        int i, numberOfKeys;

        while (currentNode != null) {
            numberOfKeys = currentNode.mCurrentKeyNum;
            i = 0;
            currentKey = currentNode.mKeys[i];
            //看看key在当前的节点的哪个区间
            while ((i < numberOfKeys) && (key.compareTo(currentKey.mKey) > 0)) {
                ++i;
                if (i < numberOfKeys) {
                    currentKey = currentNode.mKeys[i];
                }
                else {
                    --i;
                    break;
                }
            }
            //到达该节点的区间,如果key相等,则返回这个值。如果已经是叶子节点,则返回null。
            if ((i < numberOfKeys) && (key.compareTo(currentKey.mKey) == 0)) {
                return currentKey.mValue;
            } else if (currentNode.mIsLeaf) {
                return null;
            }
            
            //获取对应的区间的子节点。
            if (key.compareTo(currentKey.mKey) > 0) {
                //这里也可以从磁盘中读取对应的数。
                currentNode = BTNode.getRightChildAtIndex(currentNode, i);
            } else {
                //这里也可以从磁盘中读取对应的数。
                currentNode = BTNode.getLeftChildAtIndex(currentNode, i);
            }
        }

        return null;
    }

向B-Tree中插入一个关键字

//代更新

参考:

  1. 算法导论》
  2. https://www.codeproject.com/Articles/1158559/B-Tree-Another-Implementation-By-Java#_articleTop
  • 7
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值