B树
B树即平衡查找树,一般理解为平衡多路查找树,能对存储的数据进行O(log n)的时间复杂度进行查找、插入和删除。B树一般较多用在存储系统上,比如数据库或文件系统。
B树特点
B树可以定义一个m值作为预定范围,即m路(阶)B树。
- 每个节点最多有m个孩子。
- 每个节点至少有ceil(m/2)个孩子,除了根节点和叶子节点外。
- 对于根节点,子树个数范围为[2,m],节点内值的个数范围为[1,m-1]。
- 对于非根节点,节点内的值个数范围为[ceil(m/2)-1,m-1]。
- 根节点(非叶子节点)至少有两个孩子。
- 一个有k个孩子的非叶子节点包含k-1个值。
- 所有叶子节点在同一层。
- 节点内的值按照从小到大排列。
- 父节点的若干值作为分离值分成多个子树,左子树小于对应分离值,对应分离值小于右子树。
一颗M阶B树T,满足以下条件
- 每个节点至多拥有M棵子树
- 根结点至少拥有两棵子树
- 除了根节点以外,其余每个分支结点至少拥有M/2棵子树
- 所有叶结点都在同一层上
- 关键字数量满足ceil(M/2) - 1 <= n <= M - 1
插入操作
插入操作的核心是分裂操作。无需分裂的情况比较简单,直接插入即可;如果插入后超过节点容量,这个容量可预先自定义,则需要进行分裂操作,需要注意的是分裂可能引起父节点需要继续分裂。
超过了节点可以存放容量,对于四阶B树每个节点最多存放3个值,此时需要执行分裂操作。
分裂操作为,先选取待分裂节点的中值,这里为“B”,然后将中值“B”放到父节点中,因为这里还没有父节点,那么直接创建一个新的父节点存放“B”,而原来小于“B”的那些值作为左子树,原来大于“B”的那些值作为右子树。
继续插入
选取待分裂节点的中值“D”,然后将中值“D”放到父节点中,父节点中的“B”小于“D”,于是放到“B”右边,而原来小于“D”的那些值作为左子树,原来大于“D”的那些值作为右子树。
查找
查找过程有点类似二叉搜索树
删除
判断子树key数量M/2 - 1
M = 5 时 最小为2
子节点ABDE合并时当前点下沉
- 相邻两颗子树都是M/2 -1, 合并
- 左边子树大于M/2 - 1, 借节点
- 右边子树大于M/2 - 1,借节点
B+
B+树是B树的一种变体,也属于平衡多路查找树,大体结构与B树相同,包含根节点、内部节点和叶子节点。多用于数据库和操作系统的文件系统中,由于B+树内部节点不保存数据,所以能在内存中存放更多索引,增加缓存命中率。另外因为叶子节点相连遍历操作很方便,而且数据也具有顺序性,便于区间查找。
性质
- B+树可以定义一个m值作为预定范围,即m路(阶)B+树。
- 根节点可能是叶子节点,也可能是包含两个或两个以上子节点的节点。
- 内部节点如果拥有k个关键字则有k+1个子节点。
- 非叶子节点不保存数据,只保存关键字用作索引,所有数据都保存在叶子节点中。
- 非叶子节点有若干子树指针,如果非叶子节点关键字为k1,k2,…kn,其中n=m-1,那么第一个子树关键字判断条件为小于k1,第二个为大于等于k1而小于k2,以此类推,最后一个为大于等于kn,总共可以划分出m个区间,即可以有m个分支。(判断条件其实没有严格的要求,只要能实现对B+树的数据进行定位划分即可,有些实现使用了m个关键字来划分区间,也是可以的)
- 所有叶子节点通过指针链相连,且叶子节点本身按关键字的大小从小到大顺序排列。
- 自然插入而不进行删除操作时,叶子节点项的个数范围为[floor(m/2),m-1],内部节点项的个数范围为[ceil(m/2)-1,m-1]。
- 另外通常B+树有两个头指针,一个指向根节点一个指向关键字最小的叶子节点。
- 在进行删除操作时,涉及到索引节点填充因子和叶子节点填充因子,一般可设叶子节点和索引节点的填充因子都不少于50%。