dastal
Version:
Data Structures & Algorithms implementations
371 lines • 10.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toBinaryTree = exports.successorStack = exports.successor = exports.searchStack = exports.search = exports.rightmostStack = exports.rightmost = exports.reverse = exports.preOrderTraverse = exports.predecessorStack = exports.predecessor = exports.postOrderTraverse = exports.levelOrderTraverse = exports.inOrderTraverse = exports.leftmostStack = exports.leftmost = exports.clone = exports.removeStack = exports.debug = void 0;
const stringUtils_1 = require("src/utils/stringUtils");
/**
* [source](https://stackoverflow.com/questions/51419176/how-to-get-a-subset-of-keyof-t-whose-value-tk-are-callable-functions-in-typ)
*
* @internal
*
export type KeyOfType<T, U> = {[K in keyof T]: T[K] extends U ? K: never}[keyof T];
*/
/**
* @internal
*/
function debug(root, mapFn) {
mapFn = mapFn == null ? (n) => n.value : mapFn;
// Turn the tree into an array in level-order
const array = [];
for (const node of levelOrderTraverse(root, true)) {
array.push(node ? `${mapFn(node)}` : '?');
}
// If empty
if (array.length < 1) {
console.log('<empty>\n');
return;
}
// Find the longest value string
const lenV = array.reduce((p, c) => Math.max(p, c.length), 0);
// Pad each value
for (let i = 0; i < array.length; ++i) {
array[i] = stringUtils_1.pad(array[i], lenV, ' ');
}
// Split values into levels
const levels = [];
for (let n = 1; array.length > 0; n *= 2) {
levels.push(array.splice(0, n));
}
// Initialize formatting variables
let branch = '_'.repeat(1 + lenV / 2);
let offset = '';
const offsetOffset = ' '.repeat(branch.length);
let separator = ' '.repeat(1 + ((lenV - 1) & 1));
const separatorOffset = ' '.repeat(lenV);
// Build the last level
array.length = levels.length;
array[array.length - 1] = levels.pop().join(separator);
// Build remaining levels in reverse
for (let n = levels.length - 1; n >= 0; --n) {
const level = levels.pop();
for (let j = 0; j < level.length; ++j) {
level[j] = branch + level[j] + branch;
}
array[n] = offset + level.join(separator);
branch += branch;
offset += offset + offsetOffset;
separator += separator + separatorOffset;
}
// Output
console.log(array.join('\n'), '\n');
}
exports.debug = debug;
/**
* @internal
*/
function removeStack(stack, dir = true) {
let edge = stack.value;
let node = edge.to;
// Input check
if (node == null) {
return stack;
}
// Find the replacement
if (node.right == null) {
// If no right child, replace with left
node = node.left;
}
else if (node.left == null) {
// If no left child, replace with right
node = node.right;
}
else if (dir) {
// Replace with the successor
stack = successorStack(stack);
edge = stack.value;
const temp = edge.to;
node.value = temp.value;
node = temp.right;
}
else {
// Replace with the predecessor
stack = predecessorStack(stack);
edge = stack.value;
const temp = edge.to;
node.value = temp.value;
node = temp.left;
}
// Make the replacement / update the tree
edge.to = node;
if (edge.from) {
edge.from[edge.label] = edge.to = node;
}
return stack;
}
exports.removeStack = removeStack;
function clone(node) {
if (node == null) {
return undefined;
}
const out = Object.assign({}, node);
let stack = { value: out };
do {
node = stack.value;
stack = stack.next;
if (node.left) {
stack = { next: stack, value: (node.left = Object.assign({}, node.left)) };
}
if (node.right) {
stack = { next: stack, value: (node.right = Object.assign({}, node.right)) };
}
} while (stack);
return out;
}
exports.clone = clone;
function leftmost(node) {
if (node == null) {
return undefined;
}
while (node.left) {
node = node.left;
}
return node;
}
exports.leftmost = leftmost;
/**
* @internal
*/
function leftmostStack(stack) {
let node = stack.value.to;
if (node == null) {
return stack;
}
while (node.left) {
stack = { next: stack, value: { label: 'left', from: node, to: node.left } };
node = node.left;
}
return stack;
}
exports.leftmostStack = leftmostStack;
/**
* @internal
*/
function* inOrderTraverse(node) {
let stack = undefined;
while (node) {
stack = { next: stack, value: node };
node = node.left;
}
while (stack) {
node = stack.value;
stack = stack.next;
yield node;
node = node.right;
while (node) {
stack = { next: stack, value: node };
node = node.left;
}
}
}
exports.inOrderTraverse = inOrderTraverse;
function* levelOrderTraverse(node, padded = false) {
const nil = {};
let head = { value: node };
let tail = head;
for (let cont = node != null; cont; head = head.next) {
tail = tail.next = nil;
for (cont = false; head !== nil; head = head.next) {
node = head.value;
if (node) {
yield node;
cont || (cont = node.left != null || node.right != null);
tail = tail.next = { value: node.left };
tail = tail.next = { value: node.right };
}
else if (padded) {
yield undefined;
tail = tail.next = { value: undefined };
tail = tail.next = { value: undefined };
}
}
}
}
exports.levelOrderTraverse = levelOrderTraverse;
/**
* @internal
*/
function* postOrderTraverse(node) {
let stack = { value: { seen: false, node } };
do {
const meta = stack.value;
stack = stack.next;
if (meta.node) {
if (meta.seen) {
yield meta.node;
}
else {
meta.seen = true;
stack = { next: stack, value: meta };
stack = { next: stack, value: { seen: false, node: meta.node.right } };
stack = { next: stack, value: { seen: false, node: meta.node.left } };
}
}
} while (stack);
}
exports.postOrderTraverse = postOrderTraverse;
/**
* @internal
*/
function predecessor(node) {
return node == null ? undefined : rightmost(node.left);
}
exports.predecessor = predecessor;
/**
* @internal
*/
function predecessorStack(stack) {
const node = stack.value.to;
if (node == null) {
return stack;
}
stack = { next: stack, value: { label: 'left', from: node, to: node.left } };
return rightmostStack(stack);
}
exports.predecessorStack = predecessorStack;
/**
* @internal
*/
function* preOrderTraverse(node) {
let stack = { value: node };
do {
node = stack.value;
stack = stack.next;
if (node) {
yield node;
stack = { next: stack, value: node.right };
stack = { next: stack, value: node.left };
}
} while (stack);
}
exports.preOrderTraverse = preOrderTraverse;
/**
* @internal
*/
function reverse(root) {
if (root == null) {
return;
}
for (const node of preOrderTraverse(root)) {
const left = node.left;
node.left = node.right;
node.right = left;
}
}
exports.reverse = reverse;
function rightmost(node) {
if (node == null) {
return undefined;
}
while (node.right) {
node = node.right;
}
return node;
}
exports.rightmost = rightmost;
/**
* @internal
*/
function rightmostStack(stack) {
let node = stack.value.to;
if (node == null) {
return stack;
}
while (node.right) {
stack = { next: stack, value: { label: 'right', from: node, to: node.right } };
node = node.right;
}
return stack;
}
exports.rightmostStack = rightmostStack;
/**
* Assumes sorted by compareFn
* @internal
*/
function search(element, node, compareFn) {
while (node) {
const comp = compareFn(element, node.value);
if (comp == 0) {
break;
}
node = comp < 0 ? node.left : node.right;
}
return node;
}
exports.search = search;
/**
* Assumes sorted by compareFn
* @internal
*/
function searchStack(element, stack, compareFn, dupeWeight = 0) {
const paths = ['left', 'right'];
let node = stack.value.to;
while (node) {
const comp = compareFn(element, node.value) || dupeWeight;
if (comp === 0) {
break;
}
const label = paths[+(comp > 0)];
stack = { next: stack, value: { label, from: node, to: node[label] } };
node = node[label];
}
return stack;
}
exports.searchStack = searchStack;
/**
* @internal
*/
function successor(node) {
return node == null ? undefined : leftmost(node.right);
}
exports.successor = successor;
/**
* @internal
*/
function successorStack(stack) {
const node = stack.value.to;
if (node == null) {
return stack;
}
stack = { next: stack, value: { label: 'right', from: node, to: node.right } };
return leftmostStack(stack);
}
exports.successorStack = successorStack;
/**
* Turn an array into a binary tree. Assumes elements are in level-order.
*
* @internal
*/
function toBinaryTree(elements) {
if (elements == null || elements.length < 1 || elements[0] == null) {
return undefined;
}
const n = elements.length;
const nodes = new Array(n);
nodes[0] = { value: elements[0] };
for (let i = 1; i < n; ++i) {
if (elements[i] == null) {
continue;
}
const par = nodes[(i - 1) >>> 1];
const node = { value: elements[i] };
nodes[i] = node;
if (i & 1) {
par.left = node;
}
else {
par.right = node;
}
}
return nodes[0];
}
exports.toBinaryTree = toBinaryTree;
//# sourceMappingURL=binaryTreeUtils.js.map