B 树和 B+ 树是两种重要的平衡多路搜索树,特别适合在磁盘等外存设备上组织和存储数据。它们通过增加节点的分支因子,减少树的高度,从而减少磁盘 I/O 操作,提高数据访问效率。
B 树是一种自平衡的多路搜索树,每个节点可以有多个子节点。
class BTreeNode {
constructor(isLeaf = false) {
this.isLeaf = isLeaf;
this.keys = [];
this.children = [];
}
}
class BTree {
constructor(minDegree) {
this.root = new BTreeNode(true);
this.minDegree = minDegree; // 最小度,决定节点的最小键数和子节点数
}
// 搜索键
search(key, node = this.root) {
let i = 0;
while (i < node.keys.length && key > node.keys[i]) {
i++;
}
if (i < node.keys.length && key === node.keys[i]) {
return node;
}
if (node.isLeaf) {
return null;
}
return this.search(key, node.children[i]);
}
// 插入键
insert(key) {
const root = this.root;
if (root.keys.length === (2 * this.minDegree - 1)) {
const newRoot = new BTreeNode();
this.root = newRoot;
newRoot.children.push(root);
this.splitChild(newRoot, 0);
this.insertNonFull(newRoot, key);
} else {
this.insertNonFull(root, key);
}
}
// 在非满节点插入键
insertNonFull(node, key) {
let i = node.keys.length - 1;
if (node.isLeaf) {
node.keys.push(null);
while (i >= 0 && key < node.keys[i]) {
node.keys[i + 1] = node.keys[i];
i--;
}
node.keys[i + 1] = key;
} else {
while (i >= 0 && key < node.keys[i]) {
i--;
}
i++;
if (node.children[i].keys.length === (2 * this.minDegree - 1)) {
this.splitChild(node, i);
if (key > node.keys[i]) {
i++;
}
}
this.insertNonFull(node.children[i], key);
}
}
// 分裂子节点
splitChild(parentNode, index) {
const minDegree = this.minDegree;
const childNode = parentNode.children[index];
const newNode = new BTreeNode(childNode.isLeaf);
parentNode.children.splice(index + 1, 0, newNode);
parentNode.keys.splice(index, 0, childNode.keys[minDegree - 1]);
newNode.keys = childNode.keys.slice(minDegree);
childNode.keys = childNode.keys.slice(0, minDegree - 1);
if (!childNode.isLeaf) {
newNode.children = childNode.children.slice(minDegree);
childNode.children = childNode.children.slice(0, minDegree);
}
}
// 打印B树
printTree(node = this.root, level = 0) {
let indent = ' '.repeat(level);
console.log(indent + 'Level ' + level + ': ' + node.keys.join(', '));
if (!node.isLeaf) {
for (let i = 0; i < node.children.length; i++) {
this.printTree(node.children[i], level + 1);
}
}
}
}
// 使用示例
const bTree = new BTree(3); // 创建一个最小度为3的B树
bTree.insert(10);
bTree.insert(20);
bTree.insert(5);
bTree.insert(6);
bTree.insert(12);
bTree.insert(30);
bTree.insert(7);
bTree.insert(17);
console.log("B树结构:");
bTree.printTree();
B+ 树是 B 树的一种变体,它在数据库和文件系统中被广泛使用。
class BPlusTreeNode {
constructor(isLeaf = false) {
this.isLeaf = isLeaf;
this.keys = [];
this.children = [];
this.next = null; // 用于叶子节点之间的链接
}
}
class BPlusTree {
constructor(minDegree) {
this.root = new BPlusTreeNode(true);
this.minDegree = minDegree;
}
// 搜索键
search(key) {
let node = this.root;
while (!node.isLeaf) {
let i = 0;
while (i < node.keys.length && key > node.keys[i]) {
i++;
}
node = node.children[i];
}
// 在叶子节点中查找
for (let i = 0; i < node.keys.length; i++) {
if (node.keys[i] === key) {
return true;
}
}
return false;
}
// 插入键
insert(key) {
const root = this.root;
if (root.keys.length === (2 * this.minDegree - 1)) {
const newRoot = new BPlusTreeNode();
this.root = newRoot;
newRoot.children.push(root);
this.splitChild(newRoot, 0);
this.insertNonFull(newRoot, key);
} else {
this.insertNonFull(root, key);
}
}
// 在非满节点插入键
insertNonFull(node, key) {
let i = node.keys.length - 1;
if (node.isLeaf) {
node.keys.push(null);
while (i >= 0 && key < node.keys[i]) {
node.keys[i + 1] = node.keys[i];
i--;
}
node.keys[i + 1] = key;
} else {
while (i >= 0 && key < node.keys[i]) {
i--;
}
i++;
if (node.children[i].keys.length === (2 * this.minDegree - 1)) {
this.splitChild(node, i);
if (key > node.keys[i]) {
i++;
}
}
this.insertNonFull(node.children[i], key);
}
}
// 分裂子节点
splitChild(parentNode, index) {
const minDegree = this.minDegree;
const childNode = parentNode.children[index];
const newNode = new BPlusTreeNode(childNode.isLeaf);
parentNode.children.splice(index + 1, 0, newNode);
parentNode.keys.splice(index, 0, childNode.keys[minDegree - 1]);
newNode.keys = childNode.keys.slice(minDegree);
childNode.keys = childNode.keys.slice(0, minDegree - 1);
if (!childNode.isLeaf) {
newNode.children = childNode.children.slice(minDegree);
childNode.children = childNode.children.slice(0, minDegree);
} else {
// 处理叶子节点之间的链接
newNode.next = childNode.next;
childNode.next = newNode;
}
}
// 范围查询
rangeQuery(start, end) {
const result = [];
let node = this.root;
// 找到起始键所在的叶子节点
while (!node.isLeaf) {
let i = 0;
while (i < node.keys.length && start > node.keys[i]) {
i++;
}
node = node.children[i];
}
// 遍历叶子节点链表,收集范围内的键
while (node) {
for (let key of node.keys) {
if (key >= start && key <= end) {
result.push(key);
}
if (key > end) {
return result;
}
}
node = node.next;
}
return result;
}
// 打印B+树
printTree() {
let node = this.root;
let level = 0;
while (!node.isLeaf) {
console.log(`Level ${level}: ${node.keys.join(', ')}`);
node = node.children[0];
level++;
}
// 打印叶子节点
console.log(`Level ${level} (Leaf):`);
let leafNode = node;
let leafLevel = [];
while (leafNode) {
leafLevel.push(...leafNode.keys);
leafNode = leafNode.next;
}
console.log(leafLevel.join(', '));
}
}
// 使用示例
const bPlusTree = new BPlusTree(3);
bPlusTree.insert(10);
bPlusTree.insert(20);
bPlusTree.insert(5);
bPlusTree.insert(6);
bPlusTree.insert(12);
bPlusTree.insert(30);
bPlusTree.insert(7);
bPlusTree.insert(17);
console.log("B+树结构:");
bPlusTree.printTree();
console.log("范围查询 (5-15):", bPlusTree.rangeQuery(5, 15));
B 树和 B+ 树是现代计算机系统中非常重要的数据结构,它们通过平衡多路搜索的特性,有效地减少了磁盘 I/O 操作,提高了数据访问效率,是数据库和文件系统等应用的核心组件。