B树

1、前言

B树是为磁盘或其它直接存取的辅助存储设备而设计的一种平衡搜索树,它类似于红黑树,但它在降低磁盘I/O操作上更好,B树也常被用于数据库中。

B树的最大不同之处在于B树的结点可以有很多孩子,数十到数千都可以。因为此特性,B树的高度一般会比红黑树低很多。

ps:有种观点是B树即为普通二叉搜索树,B-树才是本文中讨论的B树,本文不采纳此观点,B-树是从B-Tree翻译过来的,翻译成B-树,这也太粗糙了。

2、B树定义

从上图可知,B树结点中,如果有n个关键字,那么就有n+1个孩子。结点x中的关键字就是分隔点,分隔成n+1个子域。

每个结点x都有以下属性:

  • x.n,当前存储在结点x中的关键字个数
  • x.n个关键字本身x.key1,x.key2,x.keyx.n,以非降序存放,使得x.key1<=x.key2<=...<=x.keyx.n
  • x.leaf,一个布尔值,如果x是叶结点,则为true,如果是内部结点,则为false
  • 每个内部结点x还包含 x.n+1 个指向其孩子的指针,x.c1,x.c2,x.cx.n+1,叶结点没有孩子,所以它们的ci属性没有定义。
  • 关键字x.keyi对存储在各子树中的关键字范围加以分割,如果ki为任意一个存储在以 x.ci 为根的子树的关键字,那么:
    k1 <= x.key1 <= k2 <= x.key2 <= ... <= x.keyx.n <= kx.n+1
  • 每个叶结点具有相同的深度,即树的高度h
  • 每个结点所包含的关键字个数有上界和下界。用一个被称为B树的最小度数的固定整数 t>=2 来表示界。
  • 除了根结点以外的每个结点必须至少有t-1个关键字,因此除了根结点以外的每个内部结点至少有t个孩子。如果树非空,根结点至少有一个关键字
  • 每个结点最多可包含 2t -1 个关键字,因为一个内部结点至多有2t 个孩子,当一个结点有 2t-1 个关键字时,该结点是满的

B树的属性有点多,尤其是最后两点,注意是除根结点以外的每个结点最少有t-1个关键字,并不是所有结点都是。

B树的特色或者精髓就在于每个结点的子结点非常多,在树高非常低的情况下就能存储大数数据。B树高度有以下定理

3、向B树中插入关键字

在普通二叉搜索树中,插入关键字,一定会新增加一个节点。但在B树中,不能简单地创建一个新的节点,新增的关键字一定是被插入已经存在的叶结点上。

如果被插入的叶结点已满,它的关键字个数为 2t-1 个,此时需要分裂结点。如图:

结点分裂是指,将一个满结点,按其中间关键字y.keyt分裂成两个各含t-1个关键字的结点,中间关键字被提升到y的父结点。如果y的父结点也是满的怎么办呢?将y的父结点也分裂即可。

/**
 * @param x 被分裂结点的父结点
 * @param i 被分列结点在父结点中的index
 * 分裂算法并不复杂,自己绘图,搞清楚上界下界,具体index等就可以了
 */
public static void btreeSplitChild(BNode x, int i){
    BNode z = new BNode();
    BNode y = x.c[i];
    //z为分裂得到的新结点
    z.leaf = y.leaf;
    z.n = t - 1;
    //将被分裂结点的后一半关键字复制给z,同时删除后一半关键字
    for (int j = 0; j < t-1; j++) {
        z.k[j] = y.k[j+t];
        y.k[j+t] = Integer.MIN_VALUE;
    }
    //将被分裂结点的后一半子结点复制给z,同时置空后一半子结点
    if (!y.leaf) {
        for (int j = 0; j < t; j++) {
            z.c[j] = y.c[j+t];
            y.c[j+t] = null;
        }
    }
    y.n = t-1;
    //后移一位x的关键字,给分裂上来的新关键字腾位置
    for (int j = x.n-1; j >= i; j--) {
        x.k[j+1] = x.k[j];
    }
    x.k[i] = y.k[t-1];
    y.k[t-1] = Integer.MIN_VALUE;
    //后移一位x的子结点,给分裂新增加的子结点腾位置
    for (int j = x.n; j >= i+1; j--) {
        x.c[j+1] = x.c[j];
    }
    x.c[i+1] = z;
    x.n = x.n+1;
}

到目前为止,提炼给B树插入新元素的三个关键点:

  • 元素一定是插入在叶结点上的

  • 如果在查找过程中,路径上的某个结点为满结点,分裂它

  • B树的高度增加只能通过分裂增长,通常是分裂根节点实现高度增长,而不能随便添加叶结点来增高,否则会违反B树性质

    public static void btreeInsertNotFull(BNode x, int k){
      int i = x.n - 1;
      if (x.leaf) {
          //如果是叶结点,根据关键字大小排序,找出k的位置即可
          while (x.n > 0 && i >= 0 && k < x.k[i]) {
              x.k[i+1] = x.k[i];
              i--;
          }
          x.k[i+1] = k;
          x.n = x.n + 1;
      }else {
          //如果是内部结点,找出k对应的子树区域
          while (x.n > 0 && i >= 0 && k < x.k[i]) {
              i= i-1;
          }
          i = i+1;
          //如果路径中有某个结点是满结点,分裂它
          if (x.c[i].n == 2*t - 1) {
              btreeSplitChild(x, i);
              if (k > x.k[i]) {
                  i = i+1;
              }
          }
          //再次在子树中递归插入
          btreeInsertNotFull(x.c[i], k);
      }
    }
    

4、B树查找

B树查找非常简单,先在当前结点中找不大于k的关键字,如果相等则返回,如果不相等,则去对应的子结点中,递归查找。

public static void find(BNode x, int k){
    int i = 0;
    while (x.n > 0 && k > x.k[i]) {
        i++;
    }
    if (i < x.n && k == x.k[i]) {
        x.print();
        System.out.println(i);
        return;
    }
    if (x.leaf) {
        System.out.println("no result");
        return;
    }
    find(x.c[i], k);
}

关于B树删除,比插入还要复杂一些,详情可看算法导论一书,本文暂时不添加这部分内容,后续再研究。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,203评论 0 25
  • 原文链接 B树 1.前言: 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(...
    非典型程序员阅读 1,156评论 0 3
  • B树 1.前言: 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balan...
    铁甲依然在_978f阅读 1,447评论 0 4
  • B-树,就是B树,B树的原英文名是B-tree,所以很多翻译为B-树,就会很多人误以为B-树是一种树、B树是另外一...
    xx1994阅读 23,706评论 1 17
  • B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right); 2.所有结点存储一个关键字; ...
    Maggie编程去阅读 807评论 1 13