B 树与B+树

\(B-\)树,即为\(B\)树,也称为多路平衡查找树。\(B\)树所有节点孩子节点最大值称为\(B\)树的阶,通常用\(m\)表示,从查找效率考虑要求\(m \ge 3\)。一棵\(m\)阶\(B\)树或者是一棵空树,或者是满足以下条件的\(m\)次的树:

  • ①定义任意非叶子结点最多只有\(m\)个儿子;
  • ②根结点的儿子数为\([2, m]\);
  • ③除根结点以外的非叶子结点的儿子数为\([⌈m/2⌉, m]\);
  • ④每个结点存放至少\(⌈m/2⌉-1\)和至多\(m-1\)个关键字;根节点至少\(1\)个关键字
  • ⑤非叶子结点的关键字个数=指向儿子的指针个数\(-1\)
  • ⑥非叶子结点的关键字:\(k[1], k[2], …, k[n]\),\(且k[i] < k[i+1]\),\(n ∈[⌈m/2⌉-1, m-1]\) ;
  • ⑦非叶子结点的指针:\(p[0], p[1], …, p[n]\);其中\(p[0]\)指向关键字小于\(k[1]\)的子树,\(p[n]\)指向关键字大于\(k[n]\)的子树,其它\(p[i]\)指向关键字属于\((k[i], k[i+1])\)的子树;
  • ⑧所有叶子节点(失败节点)在同一层,并且不带信息。 屏幕快照 2016-08-14 下午4.26.42.png

在\(B\)树中,叶子节点可看成是外部节点或查找失败的节点,需要计入到树的高度
屏幕快照 2016-08-14 下午4.33.10.png

\(B\)树的查找

  • 若比结点的第一个关键字小,则查找在该结点第一个指针指向的结点进行;
  • 若等于结点中某个关键字,则查找成功;若在两个关键字之间,则查找在它们之间的指针指向的结点进行;
  • 若比该结点所有关键字大,则查找在该结点最后一个指针指向的结点进行;
  • 若查找已经到达某个叶结点,则说明给定值对应的数据记录不存在,查找失败

因为节点内关键字有序,所以在节点内查找既可以使用顺序方法又可以使用二分查找

\(B\)树的插入

插入的过程分两步完成:

  • ➀利用前述的\(B\)树的查找算法查找关键字的插入位置。若找到,则说明该关键字已经存在,直接返回。否则查找操作必失败于某个最低层的非终端结点上。
  • ➁判断该结点是否还有空位置。即判断该结点的关键字总数是否满 足\(n \le m-1\)。
    • 若满足,则说明该结点还有空位置,直接把关键字\(k\)插入到该结点的合适位置上。
    • 若不满足,说明该结点己没有空位置,需要把结点分裂成两个。 分裂的方法是:生成一新结点。把原结点上的关键字和\(k\)按升序排序后,从中间位置把关键字(不包括中间位置的关键字)分成两部分。左部分所含关键字放在旧结点中,右部分所含关键字放在新结点中,中间位置的关键字连同新结点的存储位置插入到父结点中。如果父结点的关键字个数也超过\((m-1)\),则要再分裂,再往上插。直至这个过程传到根结点为止。 屏幕快照 2016-08-14 下午4.53.24.png屏幕快照 2016-08-14 下午4.54.50.png

\(B\)树的删除

在\(B\)树上删除关键字\(k\)的过程分两步完成:

  • ➀利用前述的\(B\)树的查找算法找出该关键字所在的结点。然后根据 \(k\)所在结点是否为最底层非叶子结点有不同的处理方法。
  • ➁若该结点为非最底层非叶子结点,且被删关键字为该结点中第\(i\)个关键字\(k[i]\),则可从指针\(p[i]\)所指的子树中找出最小关键字\(x\),代替\(k[i]\)的位置,然后在叶结点中删去\(x\),因此,把在非叶结点删除关键字\(k\)的问题就变成了删除叶子结点中的关键字的问题了。

在最底层非叶子节点删除关键字\(x\),分为\(3\)种情况

  • 直接删除关键字:如果被删关键字所在结点的原关键字个数\(n>(⌈m/2⌉-1)\),说明删去该关键字后该结点仍满足\(B\)树的定义。 屏幕快照 2016-08-14 下午5.20.15.png
  • 如果被删关键字所在结点的原关键字个数 \(n=⌈m/2⌉-1)\),说明删去该关键字后该结点将不满足B树的定义,需要调整。
    • 兄弟够借:如果其左右兄弟结点中有“多余”的关键字,即与该结点相邻的右(左)兄弟结点中的关键字数目大于\((⌈m/2⌉-1)\)。则可将右(左)兄弟结点中最小(大)关键字上移至双亲结点。而将双亲结点中小(大)于该上移关键字的关键字下移至被删关键字所在结点中。 屏幕快照 2016-08-14 下午5.21.37.png
    • 兄弟不够借:如果左右兄弟结点中没有“多余”的关键字,即与该结点相邻的右(左)兄弟结点中的关键字数目均\(等于(⌈m/2⌉-1)\)。这种情况比较复杂。需把要删除关键字的结点与其左(或右)兄弟结点以及双亲结点中分割二者的关键字合并成一个结点,即在删除关键字后,该结点中剩余的关键字加指针,加上双亲结点中的关键字\(k_i\)一起,合并到\(A_i\)(是双亲结点指向该删除关键字结点的左(右)兄弟结点的指针)所指的兄弟结点中去。如果因此使双亲结点中关键字个数小于\((⌈m/2⌉-1)\),则对此双亲结点做同样处理。以致于可能直到对根结点做这样的处理而使整个树减少一层。 屏幕快照 2016-08-14 下午5.35.22.png \(5\)阶\(B\)树 屏幕快照 2016-08-14 下午5.38.39.png

屏幕快照 2016-08-24 上午8.40.55.png
16.png

11.png

\(B+\)树的定义

  • 每个分支节点至多有\(m\)棵子树
  • 根节点或者没有子树,或者至少有两棵子树
  • 除根节点外,其他每个分支节点至少有\(⌈m/2⌉\)棵子树
  • 有\(n\)棵子树的节点有\(n\)个关键字
  • 所有叶子节点包含全部的关键字以及指向记录的指针,而且叶子节点按关键字大小顺序链接
  • 所有分支节点中仅包含它的各个子节点中最大关键字以及指向子节点的指针 屏幕快照 2016-08-14 下午6.33.49.png 图示为一棵\(B+\)树,在\(B+\)树中通常含有两个头指针,一个指向根节点,一个指向关键字最小的叶子节点。

\(m\)阶\(B+\)树和\(B\)树的区别

  • 在\(B+\)树中有\(n\)个关键字的节点含有\(n\)棵子树,即对每个关键字对应一棵子树,而在\(B\)树中,具有\(n\)个关键字的节点含有\(n+1\)棵子树
  • 在\(B+\)树中,每个节点的关键字的个数\(n\)满足\((⌈m/2⌉ \le n \le m)\),根节点为\((2 \le n \le m)\);对于\(B\)树每个节点的关键字的个数\(n\)满足\((⌈m/2⌉-1 \le n \le m-1)\),根节点为\((1<=n<=m-1)\)
  • 在\(B+\)树中,叶子节点包含全部的关键字,而其他叶子节点的关键字已经在叶子节点中了;对于\(B\)树来说关键字不是重复的

\(B+\)树的查找

  • 从最小关键字开始进行顺序查找
  • 从\(B+\)树的根开始进行随机查找,与\(B\)树查找方法相似,只是在分支节点上的关键字和查找值相等时,查找并不结束,要继续查到叶子节点为止。

\(B+\)树的插入

\(B\)树的插入仅在叶子节点插入关键字。先找到插入的节点,当插入后节点中的关键字个数大于\(m\)时要分裂成两个节点,它们所包含的关键字的个数分别为\(⌈\frac{(m+1)}{2}⌉和⌊\frac{(m+1)}{2}⌋\),同时要使得它们的双亲节点中包含这两个节点的最大关键字和指向它们的指针,若双亲节点的关键字个数大于\(m\)时要继续分裂。
屏幕快照 2016-08-14 下午7.39.14.png
往上图3阶B+树插入元素9,首先查找\(9\)应插入的叶节点(最左下角的那一个),插入发现没有破坏\(B+\)树的性质,完毕。插完如下图所示:
屏幕快照 2016-08-14 下午7.40.55.png

往下图的\(3\)阶\(B+\)树插入\(20\)
屏幕快照 2016-08-14 下午7.42.17.png
屏幕快照 2016-08-14 下午7.42.47.png

往下图4阶B+树插入100
屏幕快照 2016-08-14 下午7.54.44.png

\(B+\)树的删除

\(B+\)树的删除仅在叶子节点删除关键字。先找到要删除的节点,当删除的节点是叶子节点中的最大关键字时,应当将分支节中的次最大的值作为分界关键字

删除下图\(3阶B+\)树的关键字\(97\)
屏幕快照 2016-08-14 下午7.58.09.png

若因删除操作而使节点中关键字个数少于\(⌈m/2⌉ \)时,则从兄弟节点中调剂关键字或与兄弟节点合并,过程与\(B\)树一样
屏幕快照 2016-08-14 下午8.04.09.png
屏幕快照 2016-08-14 下午8.04.31.png
屏幕快照 2016-08-14 下午8.05.00.png

12.png
14.png
13.png

posted @ 2017-04-17 22:43  I呆呆  阅读(472)  评论(0编辑  收藏  举报