B-Tree插入和删除的Java实现
一、一颗非空m阶B-Tree的性质
- 除根结点以外的每个结点的孩子引用最多存在m个,关键码最多存在m - 1个;除根结点以外的每个结点的孩子引用至少存在⌈m / 2⌉个,关键码至少存在⌈m / 2⌉ - 1个(结点中的关键码永远比孩子引用少一个)。
- 一颗非空且的B-Tree,根结点至少存在2个孩子引用(注意:一颗非空B-Tree的根结点最少存在的孩子引用数不受m限制,且最少允许存在2个孩子引用!)。
- 每个结点的关键码遵循“左小右大”排序存放,即关键码集合中靠左的关键码小于靠右侧的关键码。
- 所有叶子结点存在同一层(可以看出B-Tree是一种严格平衡的多路搜索树)。
二、实现一颗可指定阶数的B-Tree(以下B-Tree源代码的插入和删除关键码功能均经过测试,无任何问题,可放心参考!)
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
/**
* B-Tree
* @param <K>
*/
public final class MultipleSearchTree<K> {
/**
* B-Tree Node
* @param <K>
*/
private static final class BTreeNode<K> {
K[] key; // 关键码数组
BTreeNode<K> parent; // 父结点
BTreeNode<K>[] ptr; // 孩子结点数组
int ptrSize; // 实际存在的孩子数量
BTreeNode(int order) {
// 关键码数组和指针数组都多分配一个存储空间 避免发生上溢时数组访问越界
this.key = (K[])new Object[order];
this.parent = null;
this.ptr = new BTreeNode[order + 1];
this.ptrSize = 1; // 默认至少拥有一个空孩子
}
}
private static final int FIELD_LIMIT_ORDER_MINIMUM = 3; // 阶数字段所允许的最小取值
private static final int FIELD_LIMIT_ORDER_MAXIMUM = 65535; // 阶数字段所允许的最大取值
private static final int FIELD_DEFAULT_ORDER = 4; // 阶数字段默认取值
private final Comparator<? super K> comparator; // 关键码比较器
private final int order; // 阶数
private BTreeNode<K> root; // 树根
private int keySize; // 存储的关键码数
public MultipleSearchTree(Comparator<? super K> comparator) {
checkComparator(comparator);
this.comparator = comparator;
this.order = FIELD_DEFAULT_ORDER;
}
public MultipleSearchTree(int order, Comparator<? super K> comparator) {
checkComparator(comparator);
checkOrder(order);
this.comparator = comparator;
this.order = order;
}
/**
* 阶数检查
* @param order
*/
private static void checkOrder(int order) {
if (order < FIELD_LIMIT_ORDER_MINIMUM) {
System.out.println("阶数的取值过小,最小的阶数取值不能小于" + FIELD_LIMIT_ORDER_MINIMUM + "!");
} else if (order > FIELD_LIMIT_ORDER_MAXIMUM) {
System.out.println("阶数的取值过大,最小的阶数取值不能大于" + FIELD_LIMIT_ORDER_MAXIMUM + "!");
}
}
/**
* 比较器检查
* @param comparator
* @param <K>
*/
private static <K> void checkComparator(Comparator<? super K> comparator) {
if (comparator == null) {
throw new NullPointerException("关键码比较器不能为空!");
}
}
/**
* 移除关键码
* @param key
* @return 移除成功返回true,否则返回false。
*/
public boolean remove(K key) {
if (key == null || this.root == null) {
return false;
}
final Comparator<? super K> comparator = this.comparator;
BTreeNode<K> delItr = this.root; // 关键码搜索器
int delPos = 0; // delItr.key[delPos]即为要删除的关键码
do {
delPos = Arrays.binarySearch(delItr.key, 0, delItr.ptrSize - 1, key, comparator);
if (delPos < 0) {
// 不断深入
delItr = delItr.ptr[~delPos];
} else {
break;
}
} while