话不多说,直接上代码。B树的理论网上太多了,大家自行查找学习吧
const M = 3;
class BTree {
constructor() {
/*只需要入口节点,即根节点*/
this.root = null;
}
addKey(key){
if(this.root === null){
this.root = new BTreeNode();
this.root.add(key);
return 1;
}
if(this.root.pages.length === 0){
this.root.add(key);
return 1;
}
/*一直遍历到叶子节点*/
let node = this.root;
while(node.pages.length > 0){
for(let i in node.keys){
i = parseInt(i);
if(key === node.keys[i]){
return 0;
}
if(key < node.keys[i]){
node = node.pages[i];
break;
}else if (key > node.keys[node.keys.length - 1]){
node = node.pages[node.pages.length - 1];
break;
}else{
node = node.pages[i+1];
break;
}
}
}
node.add(key);
return 1;
}
}
class BTreeNode {
constructor() {
this.parent = null;
this.keys = [];
this.pages = [];
}
add(key){
if(this.keys.length === 0){
this.keys.push(key);
return this.keys.length;
}
if(this.keys[0] > key){
/*插入头部*/
this.keys.unshift(key);
}else if(this.keys[this.keys.length - 1] < key){
/*插入尾部*/
this.keys.push(key);
}else{
/*插入中间*/
for(let i in this.keys){
if(key < this.keys[i+1] && key > this.keys[i]){
this.keys.splice(i, 0, key);
}
}
}
if(this.keys.length <= M - 1){
return this.keys.length;
}
/*一个节点数ceil(M/2) + 1 <= n <= M - 1*/
/*当节点数满了后,需要分裂*/
/*第一种分裂方式,中间的关键字上移
* ,左右的关键字变成左右子
* 每次插入的时候肯定都是子节点
*
* 分裂后,又可能导致非叶子节点的查出从而导致非叶子节点分裂
* */
if(this.parent == null){
let leftChild = new BTreeNode();
let rightChild = new BTreeNode();
leftChild.keys = this.keys.slice(0, Math.floor(this.keys.length/2));
rightChild.keys = this.keys.slice(Math.floor(this.keys.length/2) + 1, this.keys.length);
leftChild.parent = this;
rightChild.parent = this;
this.keys = [this.keys[Math.floor(this.keys.length/2)]];
leftChild.pages = this.pages.slice(0, Math.floor(this.pages.length/2));
rightChild.pages = this.pages.slice(Math.floor(this.pages.length/2), this.pages.length);
this.pages = [leftChild, rightChild];
}else{
/*先将新建的节点连接好,顺序不能错,否则分裂时丢失节点*/
/*先将一半的key分出去*/
let leftChild = new BTreeNode();
leftChild.keys = this.keys.slice(0, Math.floor(this.keys.length/2));
leftChild.parent = this.parent;
for(let i in this.parent.pages){
i = parseInt(i);
/*将新建的节点连接到父节点的pages上*/
if(this.parent.pages[i] === this){
this.parent.pages.splice(i, 0, leftChild);
break;
}
}
/*中间的key给父节点*/
this.parent.add(this.keys[Math.floor(this.keys.length/2)]);
/*自己保留右边*/
this.keys = this.keys.slice(Math.floor(this.keys.length/2) + 1, this.keys.length);
/*本节点的pages左边分配给左边,保留右边*/
leftChild.pages =[].concat(this.pages.slice(0, Math.floor(this.pages.length/2)));
this.pages = [].concat(this.pages.slice(Math.floor(this.pages.length/2), this.pages.length));
}
}
}
let btree = new BTree();
btree.addKey(53);
btree.addKey(75);
btree.addKey(139);
btree.addKey(49);
btree.addKey(145);
btree.addKey(36);
btree.addKey(101);