B树
它是一种平衡的多叉树,称为B树。 一棵M阶(M>2)的B树,是一棵平衡的M路平衡搜索树。
B树的实现:
public class BTreeNode {
public static final int KEY_LIMIT = 4;
public long[] keyList = new long[KEY_LIMIT+1];
public int size = 0;
public BTreeNode[] childList = new BTreeNode[KEY_LIMIT+2];
public BTreeNode parent = null;
@Override
public String toString() {
return String.format("%d: %s", size, Arrays.toString(Arrays.copyOf(keyList, size)));
}
public BTreeNode findKey(long key) {
if (key > keyList[size-1]) {
return childList[size];
}
for (int i = 0; i < size; i++) {
if (key == keyList[i]) {
return this;
} else if (key < keyList[i]) {
return childList[i];
}
}
return null;
}
public InsertResult insertKeyWithChild(long key, BTreeNode node) {
int index = insertIntoKeyList(key);
System.arraycopy(childList,index+1,childList,index+2,size-index);
childList[index+1] = node;
size++;
if (shouldSplit()) {
return splitNotLeaf();
}
return null;
}
private InsertResult splitNotLeaf() {
int size = this.size;
int index = size / 2;
InsertResult result = new InsertResult();
result.key = keyList[index];
BTreeNode node = new BTreeNode();
System.arraycopy(keyList,index+1,node.keyList,0,size-index-1);
node.size = size-index-1;
Arrays.fill(keyList,index,size,0);
this.size = index;
System.arraycopy(this.childList, index + 1, node.childList, 0, size - index);
Arrays.fill(this.childList, index + 1, size + 1, null);
for (int i = 0; i < size - index; i++) {
node.childList[i].parent = node;
}
node.parent = this.parent;
result.node = node;
return result;
}
public static class InsertResult{
public long key;
public BTreeNode node;
}
public InsertResult insertKey(long key) {
insertIntoKeyList(key);
size++;
if (shouldSplit( )) {
return splitLeaf();
}
return null;
}
private InsertResult splitLeaf() {
int size = this.size;
int index = size / 2;
InsertResult result = new InsertResult();
result.key = keyList[index];
BTreeNode node = new BTreeNode();
System.arraycopy(keyList,index+1,node.keyList,0,size-index-1);
node.size = size-index-1;
Arrays.fill(keyList,index,size,0);
this.size = index;
node.parent = this.parent;
result.node = node;
return result;
}
private boolean shouldSplit() {
return size > KEY_LIMIT;
}
private int insertIntoKeyList(long key) {
int i;
for (i = size-1; i >= 0; i--) {
if (keyList[i] < key) {
break;
}
keyList[i+1] = keyList[i];
}
keyList[i+1] = key;
return i+1;
}
}
public class BTree {
public BTreeNode root = null;
public int size = 0;
public boolean insert(long key) {
if (insertWithoutSize(key)) {
size++;
return true;
}
return false;
}
private boolean insertWithoutSize(long key) {
if(root == null) {
root = new BTreeNode();
root.keyList[0] = key;
root.size = 1;
return true;
}
BTreeNode cur = root;
while (true) {
BTreeNode node = cur.findKey(key);
if (node == cur) {
return false;
} else if (node == null) {
break;
} else {
cur = node;
}
}
BTreeNode.InsertResult result = cur.insertKey(key);
while (true) {
if (result == null) {
return true;
}
BTreeNode parent = cur.parent;
if (parent == null) {
root = new BTreeNode();
root.keyList[0] = result.key;
root.size = 1;
root.childList[0] = cur;
root.childList[1] = result.node;
cur.parent = result.node.parent = root;
return true;
}
result = parent.insertKeyWithChild(result.key,result.node);
cur = parent;
}
}
}
B+树
B+树的搜索与B-树基本相同,区别是B+树只有达到叶子节点才能命中(B-树可以在非叶子节点中命中)。 key一定都在叶子中保存一份。叶子节点通过链式结构关联。 数据库中常需要全key的扫描。
B+树的特性: (1)所有关键字都出现在叶子节点的链表中(稠密索引),且链表中的节点都是有序的。 (2)不可能在非叶子节点中命中。 (3) 非叶子节点相当于是叶子节点的索引(稀疏索引),叶子节点相当于是存储数据的数据层。 (4)更适合文件索引系统
B+树与B-树的区别: B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子节点存储指向关键字范围的节点;所有关键字在整棵树中出现,且只出现了一次,非叶子节点可以命中; B+树:在B-树的基础上,为叶子节点增加链表指针,所有关键字都在叶子节点中出现,非叶子节点作为叶子节点的索引;B+树总是到叶子节点才可以命中。
|