@cosmicmind/algojs
Version:
A TypeScript library featuring algorithms and data structures.
668 lines (667 loc) • 17.8 kB
JavaScript
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
};