B-树

115 阅读8分钟

进入B-树

当使用大量数据时,只能存放在硬盘中,硬盘访问次数和树的高度呈正相关

B树目的:降低树高,就是一棵多叉的平衡搜索树

用到了高速缓存,命中率高

IMG_0959.jpeg

下面的空节点称为外部节点,也叫失败节点,只是意味着查找失败

性质

B树要满足三个性质

  • 平衡
  • 有序
  • 多路

平衡

定义:所有叶子节点一定在同一层

这样整棵树就很均衡

有序

定义:B树任何一个节点内的数据都是有顺序的,且任何一个节点的左子树小于他,右子树大于他。

多路

用m表示B树的阶数,那他就是一棵m叉树。

对于m阶B树的节点

  • 最多:m个分支,m-1个元素(看图,要保证元素的个数比分支的数目少一个)
  • 最少:
    • 为根节点时:两个分支,一个元素
    • 其他节点:最少要有阶数一半的分支数(向上取整),元素数为分支数再减一

B树操作

查找

在每个节点内部可以使用折半查找或顺序查找

总体来说和二叉搜索树的查找很像,遇到失败节点意味着查找失败

访问节点是在硬盘上进行的,节点内的查找是在内存中进行的

插入

不管几阶,插入方法都是一样的,都是通过查找方法找到要插入的位置然后插入

不过插入后,可能超出节点的最大元素数量,若超过最大数量,则要做一些调整

刚完成插入操作暂未调整时,刚插入的节点一定是在叶子节点层

上溢出

调整:以中间元素,也就是第(m/2)上取整个元素,作为分割点(图中为14),把整个节点分为三部分,也就是分割点的左边,分隔点自己和分割点的右边,然后去做分裂操作,就是将分割点上移到父节点上,原来分割点的两边分割成了两个节点

IMG_0961.jpeg

IMG_0962.jpeg

总结:如果插入之后,元素个数超过了m-1,中节点上移,中节点两边分割为两个节点。

深入

中节点上移,父节点就会多一个,可能导致连锁反应

意味着分裂操作不只做一次,可能需要一直向上分裂,直到不出现上溢出

IMG_0963.jpeg

IMG_0964.jpeg

IMG_0965.jpeg

注意:分割点左右两边的元素分裂的时候,要连带着他的子数一起

调整结束

再次深入(根节点溢出)

IMG_0966.jpeg

IMG_0967.jpeg

调整方法还是一样,取中间点上移,不过这次上移之后,相当于要创建一个新的根节点,也就是树高会多一层

IMG_0968.jpeg

总结

1. 先找到插入位置进行插入(插入节点一定落在叶子节点上) 2. 如果没有上溢出,无需调整。 3. 否则中间元素上移,两边分裂,直到没有上溢出为止。

删除

插入操作比较容易出现上溢出,删除操作容易出现下溢出的情况,低于元素个数的下限

先查找到删除节点的位置,判断该元素能否被直接删掉。

如果删除的是非叶子节点的元素,都需要按照类似于二叉搜索树左右子树都有的情况,也就是用他的直接前驱或直接后继去替换他(前驱或后继肯定为叶子节点)。然后删除掉前驱或后继

也就是说删除非叶节点的元素最终都转化为删除叶节点的元素,而叶节点直接删掉就可以了

叶节点元素

  • 没有下溢出,则无需调整
  • 下溢出,尝试和左右元素兄弟借一个元素过来,要先看兄弟够不够借
    • 兄弟够借,父下来,兄上去,向能借的兄弟借一个,不能直接借,要保证借完之后B树有序的性质不能被破坏

IMG_0969.jpeg

删除68

IMG_0970.jpeg

要保证B树有序的性质不能被破坏(左 < 中 < 右),所以说要是左兄弟的元素想借过来,他俩的父亲节点65也要跟着动一下。

先把父亲节点65下移到下溢出的节点当中,然后再把左兄弟节点的最后一个元素(同理,为保证有序,用右兄弟的第一个元素)60挪上去

IMG_0971.jpeg

    • 兄弟都不够借

IMG_0972.jpeg

当左右兄弟都不够借的时候,将他和其中一个兄弟合并,但也不能直接并起来,还要考虑到他俩的父亲节点76

合并:父下移到左,然后右并过来,即父亲节点先下移到左边的节点,然后右边的节点合并过来,最后移除掉空的父元素和子树

IMG_0973.jpeg

IMG_0974.jpeg

IMG_0975.jpeg

和右兄弟合并也是父亲下移到左节点,然后右兄弟并过来(不是必须,但应该统一)

深入

父亲节点有一个元素下移,可能出现父亲节点下溢出的情况

够借

IMG_0976.jpeg

IMG_0977.jpeg

IMG_0978.jpeg

出现溢出,父下来兄上去

IMG_0979.jpeg

没有再执行合并操作,就不会下溢出了

要注意,兄弟节点是有子树的,需要把右兄弟最左边的子树也挪到左边去(借左兄弟道理一样,把最右边的子树向右挪)

再深入

IMG_0980.jpeg

左兄弟不够借,那就执行合并操作

IMG_0981.jpeg

根节点下移,右边节点并过来,注意如果右边的节点有子树的话,并过去的时候要捎带上他的子树

该例子中,删掉兄弟元素原来的位置,根节点为空,释放掉

IMG_0982.jpeg

总结

IMG_0983.jpeg