UNPKG

@cosmicmind/algojs

Version:

A TypeScript library featuring algorithms and data structures.

668 lines (667 loc) 17.8 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); import { assert, guard } from "@cosmicmind/foundationjs"; const stringCompare = /* @__PURE__ */ __name((a, b) => a === b ? 0 : a > b ? 1 : -1, "stringCompare"); const numericCompare = /* @__PURE__ */ __name((a, b) => a === b ? 0 : a > b ? 1 : -1, "numericCompare"); const stringKeyCompare = /* @__PURE__ */ __name((a, b) => a.key === b.key ? 0 : a.key > b.key ? 1 : -1, "stringKeyCompare"); const numericKeyCompare = /* @__PURE__ */ __name((a, b) => a.key === b.key ? 0 : a.key > b.key ? 1 : -1, "numericKeyCompare"); const SentinelNode = void 0; const insertionSort = /* @__PURE__ */ __name((data, fn) => { for (let i = 1, l = data.length; i < l; ++i) { const key = data[i]; let j = i - 1; while (0 <= j && 0 < fn(data[j], key)) { data[j + 1] = data[j]; --j; } data[j + 1] = key; } }, "insertionSort"); const merge = /* @__PURE__ */ __name((data, p, q, r, fn) => { const n1 = q - p + 1; const n2 = r - q; let i; let j; let k; const L = []; const R = []; for (i = 0; i < n1; ++i) { L[i] = data[p + i]; } for (j = 0; j < n2; ++j) { R[j] = data[q + j + 1]; } i = 0; j = 0; k = p; while (i < n1 && j < n2) { if (1 > fn(L[i], R[j])) { data[k] = L[i]; ++i; } else { data[k] = R[j]; ++j; } ++k; } while (i < n1) { data[k] = L[i]; ++i; ++k; } while (j < n2) { data[k] = R[j]; ++j; ++k; } }, "merge"); const sort = /* @__PURE__ */ __name((data, p, r, fn) => { if (p < r) { const q = Math.floor(p + (r - p) / 2); sort(data, p, q, fn); sort(data, q + 1, r, fn); merge(data, p, q, r, fn); } }, "sort"); const mergeSort = /* @__PURE__ */ __name((data, fn) => sort(data, 0, data.length - 1, fn), "mergeSort"); const selectionSort = /* @__PURE__ */ __name((data, fn) => { let q = 0; for (let i = 0, l = data.length; i < l; ++i) { q = i; for (let j = i + 1; j < l; ++j) { if (0 < fn(data[q], data[j])) { q = j; } } const temp = data[q]; data[q] = data[i]; data[i] = temp; } }, "selectionSort"); const heapParent = /* @__PURE__ */ __name((index) => { assert(0 <= index, "index must be 0 or greater"); return Math.floor((index - 1) / 2); }, "heapParent"); const heapLeft = /* @__PURE__ */ __name((index) => { assert(0 <= index, "index must be 0 or greater"); return 2 * index + 1; }, "heapLeft"); const heapRight = /* @__PURE__ */ __name((index) => { assert(0 <= index, "index must be 0 or greater"); return 2 * index + 2; }, "heapRight"); const heapSwapAt = /* @__PURE__ */ __name((nodes, a, b) => { assert(0 <= a, "first index must be 0 or greater"); assert(0 <= b, "second index must be 0 or greater"); const temp = nodes[a]; nodes[a] = nodes[b]; nodes[b] = temp; }, "heapSwapAt"); const heapMaxHeapify = /* @__PURE__ */ __name((nodes, size, index = 0) => { assert(0 <= size, "size must be 0 or greater"); assert(0 <= index, "index must be 0 or greater"); const left = heapLeft(index); const right = heapRight(index); let largest = left < size && nodes[left] > nodes[index] ? left : index; if (right < size && nodes[right] > nodes[largest]) { largest = right; } if (index !== largest) { heapSwapAt(nodes, index, largest); heapMaxHeapify(nodes, size, largest); } }, "heapMaxHeapify"); const heapMinHeapify = /* @__PURE__ */ __name((nodes, size, index = 0) => { assert(0 <= size, "size must be 0 or greater"); assert(0 <= index, "index must be 0 or greater"); const left = heapLeft(index); const right = heapRight(index); let largest = left < size && nodes[left] > nodes[index] ? left : index; if (right < size && nodes[right] > nodes[largest]) { largest = right; } if (index !== largest) { heapSwapAt(nodes, index, largest); heapMaxHeapify(nodes, size, largest); } }, "heapMinHeapify"); const buildMaxHeap = /* @__PURE__ */ __name((nodes) => { const size = nodes.length; for (let i = Math.floor(size / 2) - 1; 0 <= i; --i) { heapMaxHeapify(nodes, size, i); } }, "buildMaxHeap"); const buildMinHeap = /* @__PURE__ */ __name((nodes) => { const size = nodes.length; for (let i = Math.floor(size / 2); 0 <= i; --i) { heapMinHeapify(nodes, size, i); } }, "buildMinHeap"); const heapSort = /* @__PURE__ */ __name((nodes) => { buildMaxHeap(nodes); for (let i = nodes.length - 1; 0 < i; --i) { heapSwapAt(nodes, 0, i); heapMaxHeapify(nodes, i); } }, "heapSort"); const ListCompareFn = /* @__PURE__ */ __name((a, b) => a === b ? 0 : a > b ? 1 : -1, "ListCompareFn"); const listNodeCreate = /* @__PURE__ */ __name((props) => ({ ...props, next: SentinelNode, previous: SentinelNode }), "listNodeCreate"); const listCreate = /* @__PURE__ */ __name(() => ({ first: SentinelNode, last: SentinelNode, count: 0 }), "listCreate"); function listInsert(list, node) { if (guard(list.first)) { list.first.previous = node; node.next = list.first; node.previous = SentinelNode; } else { list.last = node; node.previous = SentinelNode; node.next = SentinelNode; } list.first = node; ++list.count; } __name(listInsert, "listInsert"); function listRemoveFirst(list) { const node = list.first; if (guard(node)) { const next = node.next; if (guard(next)) { list.first = next; next.previous = SentinelNode; } else { list.first = SentinelNode; list.last = SentinelNode; } node.previous = SentinelNode; node.next = SentinelNode; --list.count; } return node; } __name(listRemoveFirst, "listRemoveFirst"); function listAppend(list, node) { if (guard(list.last)) { list.last.next = node; node.previous = list.last; node.next = SentinelNode; } else { list.first = node; node.previous = SentinelNode; node.next = SentinelNode; } list.last = node; ++list.count; } __name(listAppend, "listAppend"); function listRemoveLast(list) { const node = list.last; if (guard(node)) { const previous = node.previous; if (guard(previous)) { list.last = previous; previous.next = SentinelNode; } else { list.first = SentinelNode; list.last = SentinelNode; } node.previous = SentinelNode; node.next = SentinelNode; --list.count; } return node; } __name(listRemoveLast, "listRemoveLast"); function listInsertBefore(list, insert, before, compare = ListCompareFn) { if (guard(list.first) && 0 === compare(list.first, before)) { listInsert(list, insert); } else { const previous = before.previous; if (guard(previous)) { previous.next = insert; insert.previous = previous; insert.next = before; before.previous = insert; ++list.count; } } } __name(listInsertBefore, "listInsertBefore"); function listRemoveBefore(list, before, compare = ListCompareFn) { const node = before.previous; if (guard(list.first) && guard(node) && 0 === compare(list.first, node)) { listRemoveFirst(list); } else if (guard(node)) { const previous = node.previous; if (guard(previous)) { before.previous = previous; previous.next = before; node.previous = SentinelNode; node.next = SentinelNode; --list.count; } } return node; } __name(listRemoveBefore, "listRemoveBefore"); function listInsertAfter(list, insert, after, compare = ListCompareFn) { if (guard(list.last) && 0 === compare(list.last, after)) { listAppend(list, insert); } else { const next = after.next; if (guard(next)) { next.previous = insert; insert.next = next; insert.previous = after; after.next = insert; ++list.count; } } } __name(listInsertAfter, "listInsertAfter"); function listRemoveAfter(list, after, compare = ListCompareFn) { const node = after.next; if (guard(list.last) && guard(node) && 0 === compare(list.last, node)) { listRemoveLast(list); } else if (guard(node)) { const next = node.next; if (guard(next)) { next.previous = after; after.next = next; node.previous = SentinelNode; node.next = SentinelNode; --list.count; } } return node; } __name(listRemoveAfter, "listRemoveAfter"); function listRemove(list, node, compare = ListCompareFn) { if (guard(list.first) && 0 === compare(list.first, node)) { listRemoveFirst(list); } else if (guard(list.last) && 0 === compare(list.last, node)) { listRemoveLast(list); } else { const previous = node.previous; const next = node.next; if (guard(previous) && guard(next)) { previous.next = next; next.previous = previous; node.previous = SentinelNode; node.next = SentinelNode; --list.count; } } } __name(listRemove, "listRemove"); function* listIterateFromFirst(list) { let n = list.first; while (guard(n)) { yield n; n = n.next; } } __name(listIterateFromFirst, "listIterateFromFirst"); function* listIterateFromLast(list) { let n = list.last; while (guard(n)) { yield n; n = n.previous; } } __name(listIterateFromLast, "listIterateFromLast"); function* listIterateToNext(node) { let n = node; while (guard(n)) { yield n; n = n.next; } } __name(listIterateToNext, "listIterateToNext"); function* listIterateToPrevious(node) { let n = node; while (guard(n)) { yield n; n = n.previous; } } __name(listIterateToPrevious, "listIterateToPrevious"); function listClear(list) { while (guard(list.first)) { listRemoveFirst(list); } } __name(listClear, "listClear"); function listIsFirst(list, node, compare = ListCompareFn) { return guard(list.first) && 0 === compare(list.first, node); } __name(listIsFirst, "listIsFirst"); function listIsLast(list, node, compare = ListCompareFn) { return guard(list.last) && 0 === compare(list.last, node); } __name(listIsLast, "listIsLast"); function listHas(list, node) { for (const n of listIterateFromFirst(list)) { if (n === node) { return true; } } return false; } __name(listHas, "listHas"); function listQuery(list, ...fn) { const r = /* @__PURE__ */ new Set(); loop: for (const n of listIterateFromFirst(list)) { for (const f of fn) { if (f(n)) { continue; } continue loop; } r.add(n); } return r; } __name(listQuery, "listQuery"); const StackCompareFn = /* @__PURE__ */ __name((a, b) => a === b ? 0 : -1, "StackCompareFn"); const stackNodeCreate = /* @__PURE__ */ __name((props) => ({ ...props ?? {}, parent: SentinelNode }), "stackNodeCreate"); const stackCreate = /* @__PURE__ */ __name(() => ({ top: SentinelNode, count: 0 }), "stackCreate"); function stackPeek(stack) { return stack.top; } __name(stackPeek, "stackPeek"); function stackPush(stack, node) { node.parent = stack.top; stack.top = node; ++stack.count; } __name(stackPush, "stackPush"); function stackPop(stack) { const n = stack.top; if (guard(n)) { stack.top = n.parent; n.parent = SentinelNode; --stack.count; } return n; } __name(stackPop, "stackPop"); function* stackIterator(stack) { let n = stack.top; while (guard(n)) { yield n; n = n.parent; } } __name(stackIterator, "stackIterator"); function* stackIterateFrom(node) { let n = node; while (guard(n)) { yield n; n = n.parent; } } __name(stackIterateFrom, "stackIterateFrom"); function* stackIterateToParent(node) { let n = node.parent; while (guard(n)) { yield n; n = n.parent; } } __name(stackIterateToParent, "stackIterateToParent"); function stackClear(stack) { while (guard(stack.top)) { stackPop(stack); } } __name(stackClear, "stackClear"); function stackDepth(node) { let n = node.parent; let depth = 0; while (guard(n)) { ++depth; n = n.parent; } return depth; } __name(stackDepth, "stackDepth"); function stackIsTop(stack, node, compare = StackCompareFn) { return guard(stack.top) && 0 === compare(stack.top, node); } __name(stackIsTop, "stackIsTop"); function stackHas(stack, node, compare = StackCompareFn) { for (const n of stackIterator(stack)) { if (0 === compare(n, node)) { return true; } } return false; } __name(stackHas, "stackHas"); function stackQuery(stack, ...fn) { const r = /* @__PURE__ */ new Set(); loop: for (const n of stackIterator(stack)) { for (const f of fn) { if (f(n)) { continue; } continue loop; } r.add(n); } return r; } __name(stackQuery, "stackQuery"); const TreeCompareFn = /* @__PURE__ */ __name((a, b) => a === b ? 0 : a > b ? 1 : -1, "TreeCompareFn"); const treeCreate = /* @__PURE__ */ __name((props) => ({ ...props ?? {}, parent: SentinelNode, next: SentinelNode, previous: SentinelNode, children: listCreate(), size: 1 }), "treeCreate"); function treeInsertChild(parent, node) { node.parent = parent; listInsert(parent.children, node); treeIncreaseSize(parent, node.size); } __name(treeInsertChild, "treeInsertChild"); function treeInsertChildBefore(parent, node, before, compare = TreeCompareFn) { node.parent = parent; listInsertBefore(parent.children, node, before, compare); treeIncreaseSize(parent, node.size); } __name(treeInsertChildBefore, "treeInsertChildBefore"); function treeInsertChildAfter(parent, node, after, compare = TreeCompareFn) { node.parent = parent; listInsertAfter(parent.children, node, after, compare); treeIncreaseSize(parent, node.size); } __name(treeInsertChildAfter, "treeInsertChildAfter"); function treeAppendChild(parent, node) { node.parent = parent; listAppend(parent.children, node); treeIncreaseSize(parent, node.size); } __name(treeAppendChild, "treeAppendChild"); function treeRemove(node, compare = TreeCompareFn) { const parent = node.parent; if (guard(parent)) { listRemove(parent.children, node, compare); treeDecreaseSize(parent, node.size); node.parent = SentinelNode; } } __name(treeRemove, "treeRemove"); const treeDepth = /* @__PURE__ */ __name((root) => stackDepth(root), "treeDepth"); function treeIsRoot(node) { return SentinelNode === node.parent; } __name(treeIsRoot, "treeIsRoot"); function treeIsLeaf(node) { return 0 === node.children.count; } __name(treeIsLeaf, "treeIsLeaf"); function treeIsChild(parent, node, compare = TreeCompareFn) { return guard(node.parent) && 0 === compare(node.parent, parent); } __name(treeIsChild, "treeIsChild"); function treeIsFirstChild(parent, node, compare = TreeCompareFn) { return listIsFirst(parent.children, node, compare); } __name(treeIsFirstChild, "treeIsFirstChild"); function treeIsLastChild(parent, node, compare = TreeCompareFn) { return listIsLast(parent.children, node, compare); } __name(treeIsLastChild, "treeIsLastChild"); function treeIsOnlyChild(parent, node, compare = TreeCompareFn) { return listIsFirst(parent.children, node, compare) && listIsLast(parent.children, node, compare); } __name(treeIsOnlyChild, "treeIsOnlyChild"); function treeIsChildDeep(parent, node, compare = TreeCompareFn) { let n = node.parent; while (guard(n)) { if (0 === compare(n, parent)) { return true; } n = n.parent; } return false; } __name(treeIsChildDeep, "treeIsChildDeep"); function treeIncreaseSize(root, size) { assert(0 < size, "size must be greater than 0"); for (const node of stackIterateFrom(root)) { node.size += size; } } __name(treeIncreaseSize, "treeIncreaseSize"); function treeDecreaseSize(root, size) { assert(0 < size, "size must be greater than 0"); for (const n of stackIterateFrom(root)) { n.size -= size; } } __name(treeDecreaseSize, "treeDecreaseSize"); function* depthFirstIterator(root) { yield root; for (const n of listIterateFromFirst(root.children)) { yield* depthFirstIterator(n); } } __name(depthFirstIterator, "depthFirstIterator"); function* breadthFirstIterator(root) { const queue = listCreate(); listAppend(queue, { ...root }); while (0 < queue.count) { const node = listRemoveFirst(queue); yield node; for (const q of listIterateFromFirst(node.children)) { listAppend(queue, { ...q }); } } } __name(breadthFirstIterator, "breadthFirstIterator"); function treeQuery(root, ...fn) { const r = /* @__PURE__ */ new Set(); loop: for (const node of depthFirstIterator(root)) { for (const f of fn) { if (f(node)) { continue; } continue loop; } r.add(node); } return r; } __name(treeQuery, "treeQuery"); export { ListCompareFn, SentinelNode, StackCompareFn, TreeCompareFn, breadthFirstIterator, buildMaxHeap, buildMinHeap, depthFirstIterator, heapLeft, heapMaxHeapify, heapMinHeapify, heapParent, heapRight, heapSort, heapSwapAt, insertionSort, listAppend, listClear, listCreate, listHas, listInsert, listInsertAfter, listInsertBefore, listIsFirst, listIsLast, listIterateFromFirst, listIterateFromLast, listIterateToNext, listIterateToPrevious, listNodeCreate, listQuery, listRemove, listRemoveAfter, listRemoveBefore, listRemoveFirst, listRemoveLast, mergeSort, numericCompare, numericKeyCompare, selectionSort, stackClear, stackCreate, stackDepth, stackHas, stackIsTop, stackIterateFrom, stackIterateToParent, stackIterator, stackNodeCreate, stackPeek, stackPop, stackPush, stackQuery, stringCompare, stringKeyCompare, treeAppendChild, treeCreate, treeDecreaseSize, treeDepth, treeIncreaseSize, treeInsertChild, treeInsertChildAfter, treeInsertChildBefore, treeIsChild, treeIsChildDeep, treeIsFirstChild, treeIsLastChild, treeIsLeaf, treeIsOnlyChild, treeIsRoot, treeQuery, treeRemove };