一、B树的定义
在定义B树之前,首先明确一个概念,就是什么是树的阶?
树的阶指的是一个结点最多能有多少棵子树。例如:二叉树的阶就是2。
这个要跟结点的度区分开来,度是基于单个结点的,而阶是针对整棵树的。可以理解为树的阶是用来限制每个结点的度的。
B树,又称B-树,一棵m阶的B树,或为空树,或为满足下列特性的m叉树:
(1)树中每个结点至多有m棵子树。【解释:因为树的阶是m,所有这个是必然】
(2)若根结点不是叶子节点,则至少有两棵子树。
(3)除根结点之外的所有非叶子结点至少有⌈m/2⌉棵子树。【解释:第一条是用来限制所有节点度的最大值,2、3两条是用来限制根结点和非叶子结点度的最小值】
(4)所有的非叶子结点中包含下列信息数据
(n,P0,K0,P1,K1,P2,···,Kn-1,Pn)
其中,K[i] (i=0,···,n-1)为关键字,切K[i] < K[i+1](i=0,···,n-1),P[i] (i=0,1,···,n-1)为指向子树根结点的指针,且指针P[i]所指向的子树中的所有结点的关键字均小于K[i] (i=0,···,n-1),P[i+1]所指向的子树中的所有结点的关键字均大于K[i]。n为关键字的关键字的个数,且⌈m/2⌉-1 ≤ n ≤ m-1。【解释:指的关键字的左子树都比它小,右子树都比它大】
(5)所有叶子结点位于同一层
示例,3阶B树(m=3):
二、B树的增删改查
1、B树的模型
package com.ghs.algorithm;
import java.util.List;
public class BTNode<K extends Comparable> {
/** 关键字的个数 */
private int number = 0;
/** 关键字,0号单元未使用 */
private List<K> keys;
/** 子树 */
private List<BTNode> children;
}
package com.ghs.algorithm;
public class BTree<K extends Comparable<K>>{
/** 根节点 */
private BTNode root;
/** 阶 */
private int order;
}
2、B树的查找操作
/** * @title 查询key * @author ghs * @date 2017/11/10 21:53 * @param * @return */
public Result getKey(K key){
BTNode preNode = null;
BTNode node = root;
boolean found = false;
int i = 0;
while (node != null && !found){
i = index(node, key);
if(node.getKey(i).equals(key)){
found = true;
}else{
preNode = node;
node = node.getChildren(i);
}
}
return new Result(found ? node:preNode, i, found);
}
/** * @title 查找key在node中的位置 * @author ghs * @date 2017/11/10 19:41 * @param * @return */
private int index(BTNode<K> node, K key){
//在keys[1...keyNum]中查找,使得keys[i]<= key < keys[i+1](0<i<keyNum-1)
for (int i=0; i<node.getNumber(); i++){
if (key.compareTo(node.getKey(i)) <= 0){
return i;
}
}
return node.getNumber();
}
3、B树的插入
public void addKey(K key){
Result result = getKey(key);
BTNode<K> node = result.getNode();
int position = result.getPosition();
K k = key;
BTNode<K> rightNode = null;
while (node!=null){
add(node, position, k, rightNode);
int number = node.getNumber();
if(number < order){
return;
}else {
int s = number%2==0 ? number/2 : number/2+1;
split(node, s, rightNode);
k = node.getKey(s);
node = node.getParent();
if (node != null) {
position = index(node, k);
}
}
}
newRoot(key);
}
private void split(BTNode<K> node, int s, BTNode<K> newNode){
int number = node.getNumber();
List<K> keys = node.getKeys();
List<BTNode> children = node.getChildren();
node.setKeys(keys.subList(0, s-1));
node.setChildren(children.subList(0, s));
node.setNumber(s-1);
newNode.setKeys(keys.subList(s, number-1));
newNode.setChildren(children.subList(s, number));
newNode.setNumber(number-s);
}
private BTNode newRoot(K key){
BTNode node = new BTNode();
node.addKey(0, key);
node.addChildren(0, nullBTNode);
node.addChildren(1, nullBTNode);
node.setNumber(1);
return node;
}