B树的孩子有左父亲和右父亲,父亲又有左孩子和右孩子。且一个节点既能做左孩子也能做右孩子,很奇妙的树!
文章目录
B树规则定义
一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或
者满足一下性质:
1. 根节点关键字的数量是[1,M-1]
2. 根节点孩子的数量树[2,M]
3. 每个非根节点至少有M/2(上取整)个孩子,至多有M个孩子
4. 每个非根节点至少有M/2-1(上取整)个关键字,至多有M-1个关键字
5. 所有的叶子节点都在同一层
6. 节点中关键字按升序排列,孩子永远比数据多一个
7. 孩子节点比左父亲大,比右父亲小
8. key值不会重复,原因和分裂过程有关
B树的节点由两个数组组成,上面的数组放data,下面的数组放孩子节点。
以上是定义,看完插入过程就全部理解了。
B树的插入过程
模拟一下B树的插入过程
用序列{53, 139, 75, 49, 145, 36, 101}构建B树的过程如下:
注意:插入一定是在叶子节点插入的
- 创建一个兄弟节点,然后把右半部分M / 2个数据拷贝到兄弟节点
- 再把第M / 2 - 1个节点拿走,放到根节点。理由也很简单,由于要保证孩子节点永远比数据多一,此时多了一个兄弟节点(根节点就多了一个孩子节点),因此根节点的数据也要多1.
以上就是分裂过程。
但是这并不符合搜索树的性质,因为53比75小,应该在75的左边,因此要调整顺序。调整完顺序如下:
下面是最重要的第8步,B树插入的最重要部分!!!
发现又又又要分裂了。分裂完一次之后发现根节点还要继续分裂。
注:**插入数据的时候还要更新自己孩子节点的父亲。**插入完139之后,
最终结果是这样的:
去可视化网站验证一下:确实是这样的
最后总结一下分裂过程:
- 当data个数等于M 的时候要分裂
- 分裂的时候M / 2(下取整)个的右半部分要给兄弟节点,第M / 2 个数据要给根节点。给的时候按照插入排序的思想给。
- 分裂完之后要重新把父子关系连好
- 分裂完之后还是要符合搜索二叉的性质
根据分裂过程记忆性质(重要)
- 非根节点至少有M/2-1个数据.
- 非根节点最多有M-1个数据是B树的定义。
- 非根节点至少有M/2个孩子,因为孩子比数据多1
- 非根节点最多有M个数据,这是B树的定义
B树平衡过程:只有在满了的时候才会分裂出新节点,且新节点和原节点在同一层。也就是说:新节点都是在同一层横向产生的。
根节点分裂,才会增加高度,新增一层。
总结:B树是横向和向上生长,天然就平衡的,不需要旋转
实际中,像文件系统或者数据库中用B树及其变形,索引数据。一般M都会很大,一般都会设置成1024
假设一个小块存一个字节,1w亿就是1TB了,我的手提电脑才512个G。
所以用B树的话基本上4次io就可以找到你想要的数据了。
B+树
B+树和B树规则差不多,主要差别在于
- 分裂过程稍有不同
- key值允许重复
- 叶子节点才存keyvalue结构,其余节点只存key
- 叶子节点用指针连接起来,可以看成一个链表
B+的插入过程
- B+树插入都是在叶子结点进行的,就是插入前,需要先找到要插入的叶子结点。
- 如果被插入关键字的叶子节点,当前含有的关键字数量是小于阶数m,则直接插入。
- 如果插入关键字后,叶子节点当前含有的关键字数目等于阶数m,则插,该节点开始「分裂」为两个新的节点,左边一个节点包含⌊m/2⌋ 个关键字,右边另外一个关键字包含⌈m/2⌉个关键值。(⌊m/2⌋表示向下取整,⌈m/2⌉表示向上取整,如⌈3/2⌉=2)。
- 分裂后,需要将第⌈m/2⌉的关键字上移到父结点。如果这时候父结点中包含的关键字个数小于m,则插入操作完成。
- 分裂后,需要将⌈m/2⌉的关键字上移到父结点。如果父结点中包含的关键字个数等于m,则继续分裂父结点。
举个例子:
43,48,36,32,M = 3
插入43,48,36后
由于大于两个关键字了,开始分裂。
记住左边下取整,右边上取整,然后把第M/2(上取整)个key复制给父节点
插入32
验证一下结果: