UNPKG

dastal

Version:

Data Structures & Algorithms implementations

212 lines 6.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SkewHeap = void 0; const arrayUtils_1 = require("src/utils/arrayUtils"); const binaryTreeUtils_1 = require("src/tree/binaryTreeUtils"); const binaryHeap_1 = require("./binaryHeap"); const utils_1 = require("./utils"); /** * A skew heap is a heap implemented as a binary tree * ([source](https://en.wikipedia.org/wiki/Skew_heap)). * * A skew heap is a self-adjusting heap which attempts to maintain balance * by unconditionally swapping all nodes in the merge path when merging two heaps. Every * operation that modifies the heap (e.g. push, pop, merge) is considered a merge and is done * by using a skew heap merge. * * Skew heaps can merge more quickly than binary heaps. This can seem contradictory, since * skew heaps have no structural constraints and no guarantee that the height of the tree is * logarithmic (i.e. balanced). However, amortized complexity analysis can demonstrate that * all operations on a skew heap can be done in O(log(n). More specifically, the * amortized complexity is known to be log<sub>φ</sub>(n) where φ is the golden ratio. This is * approximately 1.44*log<sub>2</sub>(n). * * #### Complexity * * | Property | Average | Worst | * | :------- | :------ | :---- | * | Space | O(n) | O(n) * | Push | O(log n) | O(log n) * | Peek | O(1) | O(1) * | Pop | O(log n) | O(log n) * | Search | O(n) | O(n) */ class SkewHeap { /** * Instantiate a heap. * * @param compareFn - The function to determine the order of elements. * @param elements - A set of elements to initialize the heap with. */ constructor(compareFn, elements) { this.compare = compareFn; this.length = 0; this.addAll(elements ?? []); } addAll(elements) { if (arrayUtils_1.isArray(elements)) { for (let i = 0; i < elements.length; ++i) { this.push(elements[i]); } } else if (elements instanceof SkewHeap || elements instanceof binaryHeap_1.BinaryHeap) { this.merge(elements); } else { for (const element of elements) { this.push(element); } } return this.length; } clear() { this.length = 0; this.root = undefined; } comparator() { return this.compare; } contains(element) { for (const node of binaryTreeUtils_1.preOrderTraverse(this.root)) { if (element === node.value) { return true; } } return false; } delete(element) { if (this.root == null) { return false; } if (this.root.value === element) { this.pop(); return true; } for (const par of binaryTreeUtils_1.preOrderTraverse(this.root)) { const key = par.left && par.left.value === element ? 'left' : par.right && par.right.value === element ? 'right' : undefined; if (key != null) { const node = par[key]; par[key] = utils_1.skewMerge(this.compare, [node.left, node.right]); --this.length; return true; } } return false; } merge(heap) { if (this.compare !== heap.comparator()) { this.addAll(heap); } else if (heap instanceof SkewHeap) { this.root = utils_1.skewMerge(this.compare, [this.root, binaryTreeUtils_1.clone(heap.root)]); this.length += heap.size; } else if (heap instanceof binaryHeap_1.BinaryHeap) { this.root = utils_1.skewMerge(this.compare, [this.root, binaryTreeUtils_1.toBinaryTree(heap['array'])]); this.length += heap.size; } else { this.addAll(heap); } return this; } peek() { return this.root?.value; } pop() { if (this.root == null) { return undefined; } const value = this.root.value; this.root = utils_1.skewMerge(this.compare, [this.root.left, this.root.right]); --this.length; return value; } push(value) { this.root = utils_1.skewMerge(this.compare, [this.root, { value }]); return ++this.length; } pushPop(value) { this.push(value); return this.pop(); } replace(value) { if (this.root == null) { this.root = { value }; this.length = 1; return undefined; } const out = this.root.value; this.root = utils_1.skewMerge(this.compare, [this.root.left, this.root.right, { value }]); return out; } get size() { return this.length; } *sorted() { if (this.root == null) { return; } const heap = new SkewHeap((a, b) => this.compare(a.value, b.value), [this.root]); do { const node = heap.pop(); yield node.value; node.left && heap.push(node.left); node.right && heap.push(node.right); } while (heap.size > 0); } /** * Receive an iterator through the list. * * **Note:** Unexpected behavior can occur if the collection is modified during iteration. * * @returns An iterator through the list */ *[Symbol.iterator]() { for (const node of binaryTreeUtils_1.preOrderTraverse(this.root)) { yield node.value; } } update(curElement, newElement) { if (this.root == null) { return false; } if (this.root.value === curElement) { this.root = utils_1.skewMerge(this.compare, [ this.root.left, this.root.right, { value: newElement }, ]); return true; } let node = undefined; for (const par of binaryTreeUtils_1.preOrderTraverse(this.root)) { if (par.left && par.left.value === curElement) { node = par.left; par.left = undefined; break; } if (par.right && par.right.value === curElement) { node = par.right; par.right = undefined; break; } } if (node == null) { return false; } this.root = utils_1.skewMerge(this.compare, [ this.root, node.left, node.right, { value: newElement }, ]); return true; } } exports.SkewHeap = SkewHeap; //# sourceMappingURL=skewHeap.js.map