进入B-树
当使用大量数据时,只能存放在硬盘中,硬盘访问次数和树的高度呈正相关
B树目的:降低树高,就是一棵多叉的平衡搜索树
用到了高速缓存,命中率高
下面的空节点称为外部节点,也叫失败节点,只是意味着查找失败
性质
B树要满足三个性质
- 平衡
- 有序
- 多路
平衡
定义:所有叶子节点一定在同一层
这样整棵树就很均衡
有序
定义:B树任何一个节点内的数据都是有顺序的,且任何一个节点的左子树小于他,右子树大于他。
多路
用m表示B树的阶数,那他就是一棵m叉树。
对于m阶B树的节点
- 最多:m个分支,m-1个元素(看图,要保证元素的个数比分支的数目少一个)
- 最少:
-
- 为根节点时:两个分支,一个元素
-
- 其他节点:最少要有阶数一半的分支数(向上取整),元素数为分支数再减一
B树操作
查找
在每个节点内部可以使用折半查找或顺序查找
总体来说和二叉搜索树的查找很像,遇到失败节点意味着查找失败
访问节点是在硬盘上进行的,节点内的查找是在内存中进行的
插入
不管几阶,插入方法都是一样的,都是通过查找方法找到要插入的位置然后插入
不过插入后,可能超出节点的最大元素数量,若超过最大数量,则要做一些调整
刚完成插入操作暂未调整时,刚插入的节点一定是在叶子节点层
上溢出
调整:以中间元素,也就是第(m/2)上取整个元素,作为分割点(图中为14),把整个节点分为三部分,也就是分割点的左边,分隔点自己和分割点的右边,然后去做分裂操作,就是将分割点上移到父节点上,原来分割点的两边分割成了两个节点
总结:如果插入之后,元素个数超过了m-1,中节点上移,中节点两边分割为两个节点。
深入
中节点上移,父节点就会多一个,可能导致连锁反应
意味着分裂操作不只做一次,可能需要一直向上分裂,直到不出现上溢出
注意:分割点左右两边的元素分裂的时候,要连带着他的子数一起
调整结束
再次深入(根节点溢出)
调整方法还是一样,取中间点上移,不过这次上移之后,相当于要创建一个新的根节点,也就是树高会多一层
总结
1. 先找到插入位置进行插入(插入节点一定落在叶子节点上) 2. 如果没有上溢出,无需调整。 3. 否则中间元素上移,两边分裂,直到没有上溢出为止。删除
插入操作比较容易出现上溢出,删除操作容易出现下溢出的情况,低于元素个数的下限
先查找到删除节点的位置,判断该元素能否被直接删掉。
如果删除的是非叶子节点的元素,都需要按照类似于二叉搜索树左右子树都有的情况,也就是用他的直接前驱或直接后继去替换他(前驱或后继肯定为叶子节点)。然后删除掉前驱或后继
也就是说删除非叶节点的元素最终都转化为删除叶节点的元素,而叶节点直接删掉就可以了
叶节点元素
- 没有下溢出,则无需调整
- 下溢出,尝试和左右元素兄弟借一个元素过来,要先看兄弟够不够借
-
- 兄弟够借,父下来,兄上去,向能借的兄弟借一个,不能直接借,要保证借完之后B树有序的性质不能被破坏
删除68
要保证B树有序的性质不能被破坏(左 < 中 < 右),所以说要是左兄弟的元素想借过来,他俩的父亲节点65也要跟着动一下。
先把父亲节点65下移到下溢出的节点当中,然后再把左兄弟节点的最后一个元素(同理,为保证有序,用右兄弟的第一个元素)60挪上去
-
- 兄弟都不够借
当左右兄弟都不够借的时候,将他和其中一个兄弟合并,但也不能直接并起来,还要考虑到他俩的父亲节点76
合并:父下移到左,然后右并过来,即父亲节点先下移到左边的节点,然后右边的节点合并过来,最后移除掉空的父元素和子树
和右兄弟合并也是父亲下移到左节点,然后右兄弟并过来(不是必须,但应该统一)
深入
父亲节点有一个元素下移,可能出现父亲节点下溢出的情况
够借
出现溢出,父下来兄上去
没有再执行合并操作,就不会下溢出了
要注意,兄弟节点是有子树的,需要把右兄弟最左边的子树也挪到左边去(借左兄弟道理一样,把最右边的子树向右挪)
再深入
左兄弟不够借,那就执行合并操作
根节点下移,右边节点并过来,注意如果右边的节点有子树的话,并过去的时候要捎带上他的子树
该例子中,删掉兄弟元素原来的位置,根节点为空,释放掉