From e38ecfac0b9e7ddae68b0060df295c15f17e73c6 Mon Sep 17 00:00:00 2001 From: Simone Spaccarotella Date: Fri, 12 Feb 2021 09:11:57 +0000 Subject: [PATCH 1/3] Added abstract interface for Heap --- src/{ => algorithms}/dfs.ts | 2 +- src/algorithms/heapWithNumbers.ts | 101 ++++++++++++++++++++++++++++++ src/collections/Collection.ts | 24 +++++++ src/collections/Comparable.ts | 17 +++++ src/collections/Heap.ts | 66 +++++++++++++++++++ src/collections/HeapArray.ts | 1 + src/collections/Stack.ts | 27 ++------ src/collections/StackArray.ts | 10 +-- src/lalla.js | 7 --- test/index.test.ts | 2 +- 10 files changed, 220 insertions(+), 37 deletions(-) rename src/{ => algorithms}/dfs.ts (94%) create mode 100644 src/algorithms/heapWithNumbers.ts create mode 100644 src/collections/Collection.ts create mode 100644 src/collections/Comparable.ts create mode 100644 src/collections/Heap.ts create mode 100644 src/collections/HeapArray.ts delete mode 100644 src/lalla.js diff --git a/src/dfs.ts b/src/algorithms/dfs.ts similarity index 94% rename from src/dfs.ts rename to src/algorithms/dfs.ts index 30096f8..38625c3 100644 --- a/src/dfs.ts +++ b/src/algorithms/dfs.ts @@ -1,4 +1,4 @@ -import BinaryNode from './BinaryNode'; +import BinaryNode from '../BinaryNode'; export function preOrder(node: BinaryNode | null, result: Array): void { if (node === null || node === undefined) return; diff --git a/src/algorithms/heapWithNumbers.ts b/src/algorithms/heapWithNumbers.ts new file mode 100644 index 0000000..1a08b04 --- /dev/null +++ b/src/algorithms/heapWithNumbers.ts @@ -0,0 +1,101 @@ +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 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 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/collections/Collection.ts b/src/collections/Collection.ts new file mode 100644 index 0000000..a73a3fa --- /dev/null +++ b/src/collections/Collection.ts @@ -0,0 +1,24 @@ +/** + * This is the base interface for all collections. + */ +export default interface Collection { + /** + * Tests if the collection is empty. + * + * @returns {boolean} true if the collection contains no items; false otherwise. + */ + isEmpty(): boolean; + + /** + * Returns the number of items stored in the collection. + * + * @returns {number} the number of items. + */ + size(): number; + + /** + * Removes all items from the collection, setting the size to zero. + * The collection will be empty after this call returns (i.e. isEmpty returns true). + */ + clear(): void; +} diff --git a/src/collections/Comparable.ts b/src/collections/Comparable.ts new file mode 100644 index 0000000..d9c09f4 --- /dev/null +++ b/src/collections/Comparable.ts @@ -0,0 +1,17 @@ +/** + * An enumeration that represents the result + * of the comparison. + */ +export enum Comparison { + GreaterThan = 1, + Equal = 0, + LessThan = -1 +} + +/** + * A class that implements this interface must define + * a way to compare its objects. + */ +export default interface Comparable { + compare(element: T): Comparison; +} diff --git a/src/collections/Heap.ts b/src/collections/Heap.ts new file mode 100644 index 0000000..498a3b5 --- /dev/null +++ b/src/collections/Heap.ts @@ -0,0 +1,66 @@ +import Collection from './Collection'; +import Comparable, { Comparison } from './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 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..7245472 --- /dev/null +++ b/src/collections/HeapArray.ts @@ -0,0 +1 @@ +// export default class HeapArray {} diff --git a/src/collections/Stack.ts b/src/collections/Stack.ts index 2361e2d..282de4f 100644 --- a/src/collections/Stack.ts +++ b/src/collections/Stack.ts @@ -1,3 +1,7 @@ +/** + * Stack is a linear data structure which follows + * the LIFO (Last In First Out) approach. + */ export default interface Stack { /** @@ -18,27 +22,4 @@ export default interface Stack { * @returns {T | undefined} the item or undefined. */ peek(): T | undefined; - - /** - * Tests if this stack is empty. - * @returns {boolean} true if and only if this stack contains no items; false otherwise. - */ - isEmpty(): boolean; - - /** - * Returns the number of items stored in the stack. - * @returns {number} the number of items. - */ - size(): number; - - /** - * Removes all of the items from the stack, setting the size to zero. The Stack will be empty after this call returns. - */ - clear(): void; - - /** - * Returns a string representation of the stack. - * @returns {string} the string representation. - */ - toString(): string; } diff --git a/src/collections/StackArray.ts b/src/collections/StackArray.ts index b7e186c..5b81014 100644 --- a/src/collections/StackArray.ts +++ b/src/collections/StackArray.ts @@ -1,6 +1,10 @@ +import Collection from './Collection'; import Stack from './Stack'; -export default class StackArray implements Stack { +/** + * This class implements the Stack interface using the JavaScript dynamic array. + */ +export default class StackArray implements Stack, Collection { private array: Array; @@ -31,8 +35,4 @@ export default class StackArray implements Stack { clear(): void { this.array.splice(0); } - - toString(): string { - return `[ ${this.array.join(' | ')} ]`; - } } diff --git a/src/lalla.js b/src/lalla.js deleted file mode 100644 index 0db4118..0000000 --- a/src/lalla.js +++ /dev/null @@ -1,7 +0,0 @@ -const a = [3, 2, 1]; - -const b = [...a]; - -console.log(b); - -console.log(a === b) diff --git a/test/index.test.ts b/test/index.test.ts index dc24d24..1f7e65e 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,5 +1,5 @@ import BinaryNode from '../src/BinaryNode'; -import { preOrder, inOrder, postOrder } from '../src//dfs'; +import { preOrder, inOrder, postOrder } from './algorithms/dfs'; import { expect } from 'chai'; const nodes = new Array>(11); From e7a8cb4d5f9f96e6915ca4293f3a9dc4d398b65f Mon Sep 17 00:00:00 2001 From: Simone Spaccarotella Date: Wed, 24 Feb 2021 07:36:22 +0000 Subject: [PATCH 2/3] update --- src/algorithms/sorting/merge-sort.ts | 5 +- src/collections/Comparable.ts | 17 ---- src/collections/Heap.ts | 5 +- src/collections/HeapArray.ts | 116 ++++++++++++++++++++++++++- src/util/Comparable.ts | 48 ++++++++--- 5 files changed, 157 insertions(+), 34 deletions(-) delete mode 100644 src/collections/Comparable.ts diff --git a/src/algorithms/sorting/merge-sort.ts b/src/algorithms/sorting/merge-sort.ts index e005ad5..7d0aa2e 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/Comparable.ts b/src/collections/Comparable.ts deleted file mode 100644 index d9c09f4..0000000 --- a/src/collections/Comparable.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * An enumeration that represents the result - * of the comparison. - */ -export enum Comparison { - GreaterThan = 1, - Equal = 0, - LessThan = -1 -} - -/** - * A class that implements this interface must define - * a way to compare its objects. - */ -export default interface Comparable { - compare(element: T): Comparison; -} diff --git a/src/collections/Heap.ts b/src/collections/Heap.ts index 498a3b5..008485b 100644 --- a/src/collections/Heap.ts +++ b/src/collections/Heap.ts @@ -1,5 +1,5 @@ import Collection from './Collection'; -import Comparable, { Comparison } from './Comparable'; +import Comparable from '../util/Comparable'; /** * A heap is a binary tree that satisfies two properties: @@ -11,7 +11,7 @@ import Comparable, { Comparison } from './Comparable'; * The items stored in this data structure must be comparable. For this reason, * it only accepts types that extends the "Comparable" interface. */ -export interface Heap> extends Collection { +export default interface Heap> extends Collection { /** * Adds a new element to the heap. * @@ -46,7 +46,6 @@ export interface Heap> extends Collection { toArray(): Array; } - // class Person implements Comparable{ // private name; diff --git a/src/collections/HeapArray.ts b/src/collections/HeapArray.ts index 7245472..ba7c14e 100644 --- a/src/collections/HeapArray.ts +++ b/src/collections/HeapArray.ts @@ -1 +1,115 @@ -// export default class HeapArray {} +import Heap from './Heap'; +import Comparable, { Comparison } from '../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/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; } From 92f6d0b7c73177bc7678596229f0bad012783d85 Mon Sep 17 00:00:00 2001 From: Simone Spaccarotella Date: Sat, 3 Jul 2021 22:54:13 +0100 Subject: [PATCH 3/3] update --- src/{algorithms => }/heapWithNumbers.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) rename src/{algorithms => }/heapWithNumbers.ts (83%) diff --git a/src/algorithms/heapWithNumbers.ts b/src/heapWithNumbers.ts similarity index 83% rename from src/algorithms/heapWithNumbers.ts rename to src/heapWithNumbers.ts index 1a08b04..c43e805 100644 --- a/src/algorithms/heapWithNumbers.ts +++ b/src/heapWithNumbers.ts @@ -14,20 +14,18 @@ class Heap { } } - - - private bubbleDown(current: number): void { - // if it is a leaf, exit + // If the current node 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); + // 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 { @@ -67,9 +65,12 @@ class Heap { 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; }