B树和B+树是在大型存储系统中,如文件系统和数据库中使用的平衡搜索树。由于它们的实现相对复杂,前端一般不会涉及。
1. B树
1.1 B树的基本属性
- B树的每个节点可能包含多个子节点。
- B树的所有叶子节点在同一层。
- 每个节点包含n个元素,按升序排列,并且有n+1个子节点。
1.2 B树的实现
定义B树节点:
class BTreeNode {
constructor(t) {
this.keys = []; // 存储关键字
this.children = []; // 子节点
this.leaf = true; // 是否是叶子节点
this.t = t; // B树的度
}
}
class BTree {
constructor(t) {
this.root = new BTreeNode(t);
this.t = t;
}
}
// 在B树中查找一个给定的关键字
BTree.prototype.search = function(node, k) {
let i = 0;
while (i < node.n && k > node.key[i]) {
i++;
}
if (i < node.n && k == node.key[i]) {
return [node, i];
} else if (node.leaf) {
return null;
} else {
return this.search(node.child[i], k);
}
}
// 插入一个关键字到B树中
BTree.prototype.insert = function(k) {
let r = this.root;
if (r.n == 2*this.t - 1) {
let s = new BTreeNode(this.t, false);
this.root = s;
s.child[0] = r;
this.splitChild(s, 0);
this.insertNonFull(s, k);
} else {
this.insertNonFull(r, k);
}
}
BTree.prototype.splitChild = function(x, i) {
let t = this.t;
let z = new BTreeNode(t);
let y = x.child[i];
z.leaf = y.leaf;
z.n = t - 1;
for (let j = 0; j < t - 1; j++) {
z.key[j] = y.key[j+t];
}
if (!y.leaf) {
for (let j = 0; j < t; j++) {
z.child[j] = y.child[j+t];
}
}
y.n = t - 1;
for (let j = x.n; j >= i+1; j--) {
x.child[j+1] = x.child[j];
}
x.child[i+1] = z;
for (let j = x.n - 1; j >= i; j--) {
x.key[j+1] = x.key[j];
}
x.key[i] = y.key[t-1];
x.n = x.n + 1;
}
BTree.prototype.insertNonFull = function(x, k) {
let i = x.n - 1;
if (x.leaf) {
while (i >= 0 && k < x.key[i]) {
x.key[i+1] = x.key[i];
i--;
}
x.key[i+1] = k;
x.n = x.n + 1;
} else {
while (i >= 0 && k < x.key[i]) {
i--;
}
i++;
if (x.child[i].n == 2*this.t - 1) {
this.splitChild(x, i);
if (k > x.key[i]) {
i++;
}
}
this.insertNonFull(x.child[i], k);
}
}
2. B+树
B+树与B树类似,但它有以下特点:
- B+树的所有值都出现在叶子节点中。
- B+树的非叶子节点只用于指示路径,所以它包含了更多的分支因子。
- B+树的所有叶子节点都是通过一个链表连接的,这对于范围查询特别有用。
class BPlusTreeNode {
constructor(t) {
this.keys = []; // 存储关键字
this.children = []; // 子节点或者实际记录
this.leaf = true; // 是否是叶子节点
this.nextSibling = null; // 下一个兄弟节点
this.t = t; // B+树的度
}
}
class BPlusTree {
constructor(t) {
this.root = new BPlusTreeNode(t);
this.t = t;
this.head = null; // 指向第一个叶子节点的指针
}
...
}