UNPKG

dastal

Version:

Data Structures & Algorithms implementations

371 lines 10.2 kB
"use strict"; 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