diff --git a/src/algorithms/sorting/merge-sort.ts b/src/algorithms/sorting/merge-sort.ts index dbb92bb..42efc5d 100644 --- a/src/algorithms/sorting/merge-sort.ts +++ b/src/algorithms/sorting/merge-sort.ts @@ -61,7 +61,10 @@ function merge(left: Array, right: Array, order: SortingOrder): /** * Sort the array of numbers in either ascending or descending order, applying the merge sort algorithm. * - * - Time complexity: O(N log(N)) where N is the size of the array. + * - Time complexity: O(N log(N)) + * - Space complexity: O(N) + * + * where N is the size of the array. * * @param input the array of numbers to sort. * @param order specify the order of sorting: ascending or descending. diff --git a/src/collections/Heap.ts b/src/collections/Heap.ts new file mode 100644 index 0000000..f4c51bd --- /dev/null +++ b/src/collections/Heap.ts @@ -0,0 +1,65 @@ +import Collection from 'src/collections/Collection'; +import Comparable from 'src/util/Comparable'; + +/** + * A heap is a binary tree that satisfies two properties: + * 1) Completeness: Every level of the tree (except last) is completely filled. + * All holes in the last level are all the way to the right. + * 2) Heap Order Invariant: Every element in the tree is <= (or >=) its parent + * depending if it's a max heap or a min heap. + * + * The items stored in this data structure must be comparable. For this reason, + * it only accepts types that extends the "Comparable" interface. + */ +export default interface Heap> extends Collection { + /** + * Adds a new element to the heap. + * + * @param element the comparable element to add. + * @complexity time: O(log n) + */ + add(element: T): void; + + /** + * Removes the root element and returns it. + * The root element can be the maximum one if it's a max heap, + * or the minimum one if it's a min heap. + * + * @returns the maximum element if a max heap, or the minimum if a min heap. + * @complexity time: O(log n) + */ + poll(): T; + + /** + * Returns the root element without removing it. + * The root element can be the maximum one if it's a max heap, + * or the minimum one if it's a min heap. + * + * @returns the maximum element if a max heap, or the minimum if a min heap. + * @complexity time: O(1) + */ + peek(); T; + + /** + * Returns the heap in array form. + */ + toArray(): Array; +} + +// class Person implements Comparable{ +// private name; + +// constructor(name: string) { +// this.name = name; +// } + +// getName() { +// return this.name; +// } + +// compare(person: Person): Comparison { +// if (this.getName() === person.getName()) return Comparison.Equal; + +// return Comparison.LessThan; +// } +// } diff --git a/src/collections/HeapArray.ts b/src/collections/HeapArray.ts new file mode 100644 index 0000000..094db9a --- /dev/null +++ b/src/collections/HeapArray.ts @@ -0,0 +1,115 @@ +import Heap from 'src/collections/Heap'; +import Comparable, { Comparison } from 'src/util/Comparable'; + +enum HeapType { + MaxHeap = 0, + MinHeap = 1 +} + +enum Operand { Left, Right }; +enum HeapType { Max, Min }; + +/** + * Returns the right operand if: + * - It's a Max Heap and the right operand is strictly greater than the left one + * - It's a Min Heap and the right operand is strictly less than the left one + * + * Returns the left operand otherwise. + * + * @param left the left operand + * @param right the right operand + * @param heapType the type of heap (Max or Min) + */ +function whoWins(left: number, right: number, heapType: HeapType): Operand { + if (heapType === HeapType.Max && right > left || heapType === HeapType.Min && right < left) { + return Operand.Right; + } else { + return Operand.Left; + } +} +export default class HeapArray> implements Heap { + + private heap: Array; + private type: HeapType; + + constructor(input: Array = [], type: HeapType = HeapType.MaxHeap) { + this.heap = input; + this.type = type; + const current = Math.floor(this.heap.length / 2); + this.buildHeap(current); + } + + private buildHeap(current: number): void { + for (let index = current; index >= 0; index--) { + this.bubbleDown(index); + } + } + + private bubbleDown(current: number): void { + // if it is a leaf, exit + if (this.isLeaf(current)) return; + // if it is greater than or equal to the greatest of its children, exit + const leftChild = this.getLeftChild(current); + const rightChild = this.getRightChild(current); + const maxChild = this.getMax(leftChild, rightChild); + if (this.heap[current] >= this.heap[maxChild]) return; + + this.swap(current, maxChild); + this.bubbleDown(maxChild); + } + + private test() { + const left = this.heap[leftChild]; + const right = this.heap[rightChild]; + const operand = whoWins(left, right); + if (operand === Operand.Left) + } + + private getMax(indexOne: number, indexTwo: number): number { + let one = this.heap[indexOne]; + let two = this.heap[indexTwo]; + if (one === undefined) return indexTwo; + if (two === undefined) return indexOne; + if (two > one) return indexTwo; + return indexOne; + } + + private swap(indexOne: number, indexTwo: number): void { + const temp = this.heap[indexOne]; + this.heap[indexOne] = this.heap[indexTwo]; + this.heap[indexTwo] = temp; + } + + private getParent(index: number): number { + return Math.floor((index - 1) / 2); + } + + private getLeftChild(index: number): number { + return index * 2 + 1; + } + + private getRightChild(index: number): number { + return index * 2 + 2; + } + + private isRoot(index: number): boolean { + return index === 0; + } + + private isLeaf(index: number): boolean { + // all elements in the second half of the array are leaves + return index >= Math.floor(this.heap.length / 2); + } + + public add(element: T): void { + + } + + public poll(): T { + throw new Error(''); + } + + public peek(); T { + throw new Error(''); + } +} diff --git a/src/collections/PriorityQueueArray.ts b/src/collections/PriorityQueueArray.ts index 9dda5a7..90b594d 100644 --- a/src/collections/PriorityQueueArray.ts +++ b/src/collections/PriorityQueueArray.ts @@ -1,4 +1,4 @@ -import QueueArray from './QueueArray.js'; +import QueueArray from 'src/collections/QueueArray'; export default class PriorityQueueArray extends QueueArray { @@ -12,8 +12,8 @@ export default class PriorityQueueArray extends QueueArray { } else { let added = false; for (let i = 0; i < super.size(); i++) { - if (item <= super.queue[i]) { - super.queue.splice(i, 0, item); + if (item <= this.queue[i]) { + this.queue.splice(i, 0, item); added = true; break; } diff --git a/src/collections/Queue.ts b/src/collections/Queue.ts index dc4d3d0..407073a 100644 --- a/src/collections/Queue.ts +++ b/src/collections/Queue.ts @@ -1,4 +1,4 @@ -import Collection from './Collection'; +import Collection from 'src/collections/Collection'; /** * The {@code Queue} interface represents a first-in-first-out diff --git a/src/collections/Stack.ts b/src/collections/Stack.ts index da3e1d6..129c905 100644 --- a/src/collections/Stack.ts +++ b/src/collections/Stack.ts @@ -1,4 +1,4 @@ -import Collection from './Collection'; +import Collection from 'src/collections/Collection'; /** * The {@code Stack} interface represents a last-in-first-out diff --git a/src/collections/StackArray.ts b/src/collections/StackArray.ts index 06794e3..f136d2b 100644 --- a/src/collections/StackArray.ts +++ b/src/collections/StackArray.ts @@ -1,5 +1,8 @@ import Stack from 'src/collections/Stack'; +/** + * This class implements the Stack interface using the JavaScript dynamic array. + */ export default class StackArray implements Stack { private stack: Array; diff --git a/src/heapWithNumbers.ts b/src/heapWithNumbers.ts new file mode 100644 index 0000000..c43e805 --- /dev/null +++ b/src/heapWithNumbers.ts @@ -0,0 +1,102 @@ +class Heap { + + private heap: Array; + + constructor(input: Array = []) { + this.heap = input; + const current = Math.floor(this.heap.length / 2); + this.buildHeap(current); + } + + private buildHeap(current: number): void { + for (let index = current; index >= 0; index--) { + this.bubbleDown(index); + } + } + + private bubbleDown(current: number): void { + // If the current node is a leaf, exit + if (this.isLeaf(current)) return; + // Get the max child + const maxChild = this.getMax(this.getLeftChild(current), this.getRightChild(current)); + // If the current node is smaller than the max child + if (this.heap[current] < this.heap[maxChild]) { + // swap positio between the current node and its child + this.swap(current, maxChild); + // recursively call this function + this.bubbleDown(maxChild); + } + } + + private bubbleUp(current: number): void { + // if it is root, exit + if (this.isRoot(current)) return; + // if it is not strictly greater than its parent, exit + const parent = this.getParent(current); + if (this.heap[current] <= this.heap[parent]) return; + + this.swap(current, parent); + this.bubbleUp(parent); + } + + private getParent(index: number): number { + return Math.floor((index - 1) / 2); + } + + private getLeftChild(index: number): number { + return index * 2 + 1; + } + + private getRightChild(index: number): number { + return index * 2 + 2; + } + + private isRoot(index: number): boolean { + return index === 0; + } + + private isLeaf(index: number): boolean { + const leftChild = this.getLeftChild(index); + const rightChild = this.getRightChild(index); + const N = this.heap.length; + return leftChild >= N && rightChild >= N; + } + + private getMax(indexOne: number, indexTwo: number): number { + let one = this.heap[indexOne]; + let two = this.heap[indexTwo]; + + if (one === undefined) return indexTwo; + if (two === undefined) return indexOne; + + if (two > one) return indexTwo; + + return indexOne; + } + + private swap(indexOne: number, indexTwo: number): void { + const temp = this.heap[indexOne]; + this.heap[indexOne] = this.heap[indexTwo]; + this.heap[indexTwo] = temp; + } +} + + +const h = new Heap([2, 4, 7, 1, 5, 3]); +// const h = new Heap(); +// h.add(2).add(4).add(7).add(1).add(5).add(3); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); +console.log(h.getRoot()); +console.log(h.toArray()); diff --git a/src/util/Comparable.ts b/src/util/Comparable.ts index 6e331e6..ab42779 100644 --- a/src/util/Comparable.ts +++ b/src/util/Comparable.ts @@ -1,19 +1,43 @@ /** - * An enumeration that represents the result - * of the comparison. + * A comparable object. */ -export enum Comparison { - EqualTo = 1, - LessThan = 2, - GreaterThan = 4, - LessThanOrEqualTo = 3, - GreaterThanOrEqualTo = 5 +export default interface Comparable { + compare(item: T): ComparisonOperator; } /** - * A class that implements this interface must define - * a way to compare its objects. + * An enumeration that represents the comparison operator: + * - EqualTo: "=" + * - LessThan: "<" (strictly less than) + * - GreaterThan: ">" (strictly greater than) */ -export default interface Comparable { - compare(element: T): Comparison; +export enum ComparisonOperator { EqualTo, LessThan, GreaterThan }; + +/** + * + */ +export enum ComparisonType { Max, Min }; + +/** + * An enumeration that represents the left and right operands of a comparison. + */ +export enum Operand { Left, Right }; + +/** + * Tells which operand wins based on the comparison type (i.e. max or min). + * @param leftOperand + * @param rightOperand + * @param comparisonType + */ +export function whoWins>(leftOperand: T, rightOperand: T, comparisonType: ComparisonType): Operand { + const comparison = rightOperand.compare(leftOperand); + + if ( + comparisonType === ComparisonType.Max && comparison === ComparisonOperator.GreaterThan || + comparisonType === ComparisonType.Min && comparison === ComparisonOperator.LessThan + ) { + return Operand.Right; + } + + return Operand.Left; }