samples/2022/03/algorithms/btree.js

203 lines
4.7 KiB
JavaScript

"use strict";
// const fs = require('fs');
// const {EOL} = require('os');
let enable_logging = false;
function log(...s) {
if (!enable_logging) {
return;
}
console.log.apply(null, s);
}
function make_node(k) {
return {
level: k,
// temporarily allowing having one more element before split
keys: [], // k node can have k-1 keys, they are sorted
children: [] // k node can have k children
};
};
function binary_search(arr, el) {
if (!arr.length) {
log('Arr is empty');
return 0;
}
if (el < arr[0]) {
log(`El ${el} is smaller than ${arr[0]}`);
return 0;
}
if (el > arr[arr.length - 1]) {
log(`El ${el} is bigger than ${arr[arr.length - 1]}`);
return arr.length;
}
let i = 0;
let j = arr.length - 1;
let p;
while (i < j - 1) {
p = (i + j) >> 1; // dividing by 2 but javascript can't do it without Math.floor
if (arr[p] <= el) {
i = p;
} else {
j = p;
}
}
return i+1;
}
function btree_insert(node, el) {
log(`Adding ${el} into`, node);
if (!node) {
return [null, el, null];
}
const idx = binary_search(node.keys, el);
log(`Got index ${idx}`);
const child = node.children[idx];
let result = btree_insert(child, el);
if (!result) {
log('No merging root from sub');
return null; // we are all good
}
let [left, root, right] = result;
log(`Got new root ${root} and sub trees`, left, right);
node.keys.splice(idx, 0, root);
node.children[idx] = left;
node.children.splice(idx+1, 0, right);
log(`Node size: ${node.keys.length}, node level: ${node.level}`);
if (node.keys.length > node.level) {
let h = node.level >> 1;
log(`Splitting`);
log(node.keys, `h index ${h}`);
let left = make_node(node.level);
let right = make_node(node.level);
let root = node.keys[h];
console.log(`Children`, node.children);
left.keys = node.keys.slice(0, h);
left.children = node.children.slice(0, h+1);
right.keys = node.keys.slice(h+1);
right.children = node.children.slice(h+1);
log('Result', left, root, right);
return [left, root, right];
} else {
return null;
}
}
function make_tree(t, result) {
if (!result) {
return t;
}
let [left, el, right] = result;
let root = make_node(t.level);
root.keys[0] = el;
root.children[0] = left;
root.children[1] = right;
return root;
}
function display_tree(t, path = '') {
if (!t) {
return;
}
for (let i = 0; i < t.keys.length; i++) {
display_tree(t.children[i], path + "/" + i);
console.log(path + " " + t.keys[i]);
}
display_tree(t.children[t.keys.length], path + "/" + t.keys.length);
}
function btree_delete(t, el) {
console.log(`Got t`, t, `, el: ${el}`);
if (!t) {
return t;
}
let idx = binary_search(t.keys, el);
let val = t.keys[idx];
console.log(`Got index ${idx} with value ${t.keys[idx]}`);
if (t.keys[idx] === el || t.keys[idx-1] === el) {
// we need to delete this element
console.log(`Found key ${el}`);
let idxEl = t.keys[idx] === el ? idx : idx - 1;
console.log(`Found idx ${idxEl}`);
if (!t.children[idx]) {
t.keys.splice(idxEl, 1);
t.children.splice(idxEl, 1);
} else {
if (t[idx-1].keys >= t.level/2) {
// we can borrow one element from precedessing
} else if (t[idx+1].keys >= t.level/2) {
// we can borrow one element from successor
} else {
}
}
// TODO check if there are enough elements to be balanced
} else {
return btree_delete(t.children[idx], el);
}
}
// let arr = [1, 3, 5, 7];
// const el = -2;
// const pos = binary_search(arr, el);
// arr.splice(pos, 0, el);
// log(`Binary search`, arr);
// let t = make_node(2);
// t = make_tree(t, btree_insert(t, 1));
// t = make_tree(t, btree_insert(t, 2));
// t = make_tree(t, btree_insert(t, 3));
// t = make_tree(t, btree_insert(t, 4));
// t = make_tree(t, btree_insert(t, 5));
// t = make_tree(t, btree_insert(t, 6));
// t = make_tree(t, btree_insert(t, 7));
// display_tree(t);
// enable_logging = true;
// t = make_tree(t, btree_insert(t, 1));
// t = make_tree(t, btree_insert(t, 2));
// t = make_tree(t, btree_insert(t, 3));
// t = make_tree(t, btree_insert(t, 4));
// t = make_tree(t, btree_insert(t, 5));
// t = make_tree(t, btree_insert(t, 6));
// t = make_tree(t, btree_insert(t, 7));
// t = make_tree(t, btree_insert(t, 8));
// t = make_tree(t, btree_insert(t, 5));
// t = make_tree(t, btree_insert(t, 5));
// console.log(t);
//enable_logging = false;
// display_tree(t);
let t = make_node(4);
enable_logging = false;
t = make_tree(t, btree_insert(t, 1));
t = make_tree(t, btree_insert(t, 2));
t = make_tree(t, btree_insert(t, 3));
t = make_tree(t, btree_insert(t, 4));
t = make_tree(t, btree_insert(t, 5));
t = make_tree(t, btree_insert(t, 6));
t = make_tree(t, btree_insert(t, 7));
enable_logging = true;
t = make_tree(t, btree_delete(t, 5));
enable_logging = false;
display_tree(t);