diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ed95b..336c74e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file. - [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - [`auto-changelog`](https://github.com/CookPete/auto-changelog) -## [v1.47.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.47.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index bf40be1..971d648 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -313,12 +313,14 @@ export class HashMap { * @returns a new HashMap object that contains the key-value pairs from the original HashMap that * satisfy the given predicate function. */ - filter(predicate: (element: [K, V], map: HashMap) => boolean): HashMap { + filter(predicate: (element: [K, V], index: number, map: HashMap) => boolean): HashMap { const filteredMap = new HashMap(); + let index = 0; for (const [key, value] of this) { - if (predicate([key, value], this)) { + if (predicate([key, value], index, this)) { filteredMap.set(key, value); } + index++; } return filteredMap; } @@ -330,11 +332,13 @@ export class HashMap { * `map`. * @returns a new HashMap object with the values mapped according to the provided callback function. */ - map(callback: (element: [K, V], map: HashMap) => NV): HashMap { + map(callback: (element: [K, V], index: number, map: HashMap) => NV): HashMap { const mappedMap = new HashMap(); + let index = 0; for (const [key, value] of this) { - const newValue = callback([key, value], this); + const newValue = callback([key, value], index, this); mappedMap.set(key, newValue); + index++; } return mappedMap; } @@ -351,10 +355,12 @@ export class HashMap { * @returns The `reduce` function is returning the final value of the accumulator after iterating * over all the elements in the HashMap and applying the callback function to each element. */ - reduce(callback: (accumulator: A, element: [K, V], map: HashMap) => A, initialValue: A): A { + reduce(callback: (accumulator: A, element: [K, V], index: number, map: HashMap) => A, initialValue: A): A { let accumulator = initialValue; - for (const element of this) { - accumulator = callback(accumulator, element, this); + let index = 0; + for (const entry of this) { + accumulator = callback(accumulator, entry, index, this); + index++; } return accumulator; } diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index 691bb79..3176e87 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -9,18 +9,18 @@ export class HashTableNode { key: K; value: V; - next: HashTableNode | null; + next: HashTableNode | undefined; constructor(key: K, value: V) { this.key = key; this.value = value; - this.next = null; + this.next = undefined; } } import { HashFunction } from '../../types'; -export class HashTable { +export class HashTable { protected static readonly DEFAULT_CAPACITY = 16; protected static readonly LOAD_FACTOR = 0.75; @@ -28,7 +28,7 @@ export class HashTable { this._hashFn = hashFn || this._defaultHashFn; this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY); this._size = 0; - this._buckets = new Array | null>(this._capacity).fill(null); + this._buckets = new Array | undefined>(this._capacity).fill(undefined); } protected _capacity: number; @@ -43,9 +43,9 @@ export class HashTable { return this._size; } - protected _buckets: Array | null>; + protected _buckets: Array | undefined>; - get buckets(): Array | null> { + get buckets(): Array | undefined> { return this._buckets; } @@ -125,7 +125,7 @@ export class HashTable { delete(key: K): void { const index = this._hash(key); let currentNode = this._buckets[index]; - let prevNode: HashTableNode | null = null; + let prevNode: HashTableNode | undefined = undefined; while (currentNode) { if (currentNode.key === key) { @@ -135,7 +135,7 @@ export class HashTable { this._buckets[index] = currentNode.next; } this._size--; - currentNode.next = null; // Release memory + currentNode.next = undefined; // Release memory return; } prevNode = currentNode; @@ -143,6 +143,56 @@ export class HashTable { } } + * [Symbol.iterator](): Generator<[K, V], void, undefined> { + for (const bucket of this._buckets) { + let currentNode = bucket; + while (currentNode) { + yield [currentNode.key, currentNode.value]; + currentNode = currentNode.next; + } + } + } + + forEach(callback: (entry: [K, V], index: number, table: HashTable) => void): void { + let index = 0; + for (const entry of this) { + callback(entry, index, this); + index++; + } + } + + filter(predicate: (entry: [K, V], index: number, table: HashTable) => boolean): HashTable { + const newTable = new HashTable(); + let index = 0; + for (const [key, value] of this) { + if (predicate([key, value], index, this)) { + newTable.set(key, value); + } + index++; + } + return newTable; + } + + map(callback: (entry: [K, V], index: number, table: HashTable) => T): HashTable { + const newTable = new HashTable(); + let index = 0; + for (const [key, value] of this) { + newTable.set(key, callback([key, value], index, this)); + index++; + } + return newTable; + } + + reduce(callback: (accumulator: T, entry: [K, V], index: number, table: HashTable) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const entry of this) { + accumulator = callback(accumulator, entry, index, this); + index++; + } + return accumulator; + } + /** * The function `_defaultHashFn` calculates the hash value of a given key and returns the remainder when divided by the * capacity of the data structure. @@ -241,7 +291,7 @@ export class HashTable { */ protected _expand(): void { const newCapacity = this._capacity * 2; - const newBuckets = new Array | null>(newCapacity).fill(null); + const newBuckets = new Array | undefined>(newCapacity).fill(undefined); for (const bucket of this._buckets) { let currentNode = bucket; diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 6978fda..3e1eca2 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -226,29 +226,30 @@ export class Heap { * @param order - Traverse order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order). * @returns An array containing elements traversed in the specified order. */ - dfs(order: DFSOrderPattern): E[] { + dfs(order: DFSOrderPattern = 'pre'): E[] { const result: E[] = []; // Auxiliary recursive function, traverses the binary heap according to the traversal order - const dfsHelper = (index: number) => { + const _dfs = (index: number) => { + const left = 2 * index + 1, right = left + 1; if (index < this.size) { if (order === 'in') { - dfsHelper(2 * index + 1); + _dfs(left); result.push(this.elements[index]); - dfsHelper(2 * index + 2); + _dfs(right); } else if (order === 'pre') { result.push(this.elements[index]); - dfsHelper(2 * index + 1); - dfsHelper(2 * index + 2); + _dfs(left); + _dfs(right); } else if (order === 'post') { - dfsHelper(2 * index + 1); - dfsHelper(2 * index + 2); + _dfs(left); + _dfs(right); result.push(this.elements[index]); } } }; - dfsHelper(0); // Traverse starting from the root node + _dfs(0); // Traverse starting from the root node return result; } @@ -324,6 +325,56 @@ export class Heap { for (let i = Math.floor(this.size / 2); i >= 0; i--) this._sinkDown(i, this.elements.length >> 1); } + * [Symbol.iterator]() { + for (const element of this.elements) { + yield element; + } + } + + forEach(callback: (element: E, index: number, heap: this) => void): void { + let index = 0; + for (const el of this) { + callback(el, index, this); + index++; + } + } + + filter(predicate: (element: E, index: number, heap: Heap) => boolean): Heap { + const filteredHeap: Heap = new Heap({ comparator: this.comparator }); + let index = 0; + for (const el of this) { + if (predicate(el, index, this)) { + filteredHeap.push(el); + } + index++; + } + return filteredHeap; + } + + map(callback: (element: E, index: number, heap: Heap) => T, comparator: Comparator): Heap { + + const mappedHeap: Heap = new Heap({ comparator: comparator }); + let index = 0; + for (const el of this) { + mappedHeap.add(callback(el, index, this)); + index++; + } + return mappedHeap; + } + + reduce( + callback: (accumulator: T, currentValue: E, currentIndex: number, heap: Heap) => T, + initialValue: T + ): T { + let accumulator: T = initialValue; + let index = 0; + for (const el of this) { + accumulator = callback(accumulator, el, index, this); + index++; + } + return accumulator; + } + /** * Time Complexity: O(log n) * Space Complexity: O(1) diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 2499e87..d7b9b90 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -441,6 +441,50 @@ export class DoublyLinkedList { return false; } + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(1) + * + * The `insertAfter` function inserts a new node with a given value after an existing node in a doubly linked list. + * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list + * after which the new value will be inserted. It can be either the value of the existing node or the existing node + * itself. + * @param {E} newValue - The value that you want to insert into the doubly linked list. + * @returns The method returns a boolean value. It returns true if the insertion is successful, and false if the + * existing value or node is not found in the doubly linked list. + */ + insertAfter(existingValueOrNode: E | DoublyLinkedListNode, newValue: E): boolean { + let existingNode; + + if (existingValueOrNode instanceof DoublyLinkedListNode) { + existingNode = existingValueOrNode; + } else { + existingNode = this.getNode(existingValueOrNode); + } + + if (existingNode) { + const newNode = new DoublyLinkedListNode(newValue); + newNode.next = existingNode.next; + if (existingNode.next) { + existingNode.next.prev = newNode; + } + newNode.prev = existingNode; + existingNode.next = newNode; + if (existingNode === this.tail) { + this._tail = newNode; + } + this._length++; + return true; + } + + return false; + } + /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(1) @@ -511,28 +555,6 @@ export class DoublyLinkedList { return false; } - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - * - * The `toArray` function converts a linked list into an array. - * @returns The `toArray()` method is returning an array of type `E[]`. - */ - toArray(): E[] { - const array: E[] = []; - let current = this.head; - while (current) { - array.push(current.value); - current = current.next; - } - return array; - } - /** * The function checks if a variable has a length greater than zero and returns a boolean value. * @returns A boolean value is being returned. @@ -631,28 +653,6 @@ export class DoublyLinkedList { return null; } - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - * - * The `toArrayBackward` function converts a doubly linked list into an array in reverse order. - * @returns The `toArrayBackward()` function returns an array of type `E[]`. - */ - toArrayBackward(): E[] { - const array: E[] = []; - let current = this.tail; - while (current) { - array.push(current.value); - current = current.prev; - } - return array; - } - /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(1) @@ -674,6 +674,62 @@ export class DoublyLinkedList { } } + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `toArray` function converts a linked list into an array. + * @returns The `toArray()` method is returning an array of type `E[]`. + */ + toArray(): E[] { + const array: E[] = []; + let current = this.head; + while (current) { + array.push(current.value); + current = current.next; + } + return array; + } + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `toReversedArray` function converts a doubly linked list into an array in reverse order. + * @returns The `toReversedArray()` function returns an array of type `E[]`. + */ + toReversedArray(): E[] { + const array: E[] = []; + let current = this.tail; + while (current) { + array.push(current.value); + current = current.prev; + } + return array; + } + + /** + * The function returns an iterator that iterates over the values of a linked list. + */ + * [Symbol.iterator]() { + let current = this.head; + + while (current) { + yield current.value; + current = current.next; + } + } + /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(1) @@ -688,42 +744,14 @@ export class DoublyLinkedList { * represents the value of the current node in the linked list, and the index argument represents the index of the * current node in the linked list. */ - forEach(callback: (value: E, index: number) => void): void { - let current = this.head; + forEach(callback: (value: E, index: number, list: DoublyLinkedList) => void): void { let index = 0; - while (current) { - callback(current.value, index); - current = current.next; + for (const el of this) { + callback(el, index, this); index++; } } - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(n) - * - * The `map` function takes a callback function and applies it to each element in the DoublyLinkedList, returning a new - * DoublyLinkedList with the transformed values. - * @param callback - The callback parameter is a function that takes a value of type E (the type of values stored in - * the original DoublyLinkedList) and returns a value of type U (the type of values that will be stored in the mapped - * DoublyLinkedList). - * @returns The `map` function is returning a new instance of `DoublyLinkedList` that contains the mapped values. - */ - map(callback: (value: E) => U): DoublyLinkedList { - const mappedList = new DoublyLinkedList(); - let current = this.head; - while (current) { - mappedList.push(callback(current.value)); - current = current.next; - } - return mappedList; - } - /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(n) @@ -739,18 +767,45 @@ export class DoublyLinkedList { * It is used to determine whether a value should be included in the filtered list or not. * @returns The filtered list, which is an instance of the DoublyLinkedList class. */ - filter(callback: (value: E) => boolean): DoublyLinkedList { + filter(callback: (value: E, index: number, list: DoublyLinkedList) => boolean): DoublyLinkedList { const filteredList = new DoublyLinkedList(); - let current = this.head; - while (current) { - if (callback(current.value)) { - filteredList.push(current.value); + let index = 0; + for (const current of this) { + if (callback(current, index, this)) { + filteredList.push(current); } - current = current.next; + index++; } return filteredList; } + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `map` function takes a callback function and applies it to each element in the DoublyLinkedList, returning a new + * DoublyLinkedList with the transformed values. + * @param callback - The callback parameter is a function that takes a value of type E (the type of values stored in + * the original DoublyLinkedList) and returns a value of type T (the type of values that will be stored in the mapped + * DoublyLinkedList). + * @returns The `map` function is returning a new instance of `DoublyLinkedList` that contains the mapped values. + */ + map(callback: (value: E, index: number, list: DoublyLinkedList) => T): DoublyLinkedList { + const mappedList = new DoublyLinkedList(); + let index = 0; + for (const current of this) { + mappedList.push(callback(current, index, this)); + index++; + } + + return mappedList; + } + /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(n) @@ -764,74 +819,19 @@ export class DoublyLinkedList { * single value. * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `value`. It is * used to perform a specific operation on each element of the linked list. - * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting + * @param {T} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting * point for the reduction operation. * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the * elements in the linked list. */ - reduce(callback: (accumulator: U, value: E) => U, initialValue: U): U { + reduce(callback: (accumulator: T, value: E, index: number, list: DoublyLinkedList) => T, initialValue: T): T { let accumulator = initialValue; - let current = this.head; - while (current) { - accumulator = callback(accumulator, current.value); - current = current.next; + let index = 0; + for (const current of this) { + accumulator = callback(accumulator, current, index, this); + index++; } + return accumulator; } - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(1) - * - * The `insertAfter` function inserts a new node with a given value after an existing node in a doubly linked list. - * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list - * after which the new value will be inserted. It can be either the value of the existing node or the existing node - * itself. - * @param {E} newValue - The value that you want to insert into the doubly linked list. - * @returns The method returns a boolean value. It returns true if the insertion is successful, and false if the - * existing value or node is not found in the doubly linked list. - */ - insertAfter(existingValueOrNode: E | DoublyLinkedListNode, newValue: E): boolean { - let existingNode; - - if (existingValueOrNode instanceof DoublyLinkedListNode) { - existingNode = existingValueOrNode; - } else { - existingNode = this.getNode(existingValueOrNode); - } - - if (existingNode) { - const newNode = new DoublyLinkedListNode(newValue); - newNode.next = existingNode.next; - if (existingNode.next) { - existingNode.next.prev = newNode; - } - newNode.prev = existingNode; - existingNode.next = newNode; - if (existingNode === this.tail) { - this._tail = newNode; - } - this._length++; - return true; - } - - return false; - } - - /** - * The function returns an iterator that iterates over the values of a linked list. - */ - * [Symbol.iterator]() { - let current = this.head; - - while (current) { - yield current.value; - current = current.next; - } - } } diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index c1a26f0..d7372f0 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -665,111 +665,6 @@ export class SinglyLinkedList { return count; } - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as it needs to reverse the pointers of each node. - * Space Complexity: O(1) - Constant space. - */ - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as it needs to reverse the pointers of each node. - * Space Complexity: O(1) - Constant space. - * - * The `forEach` function iterates over each element in a linked list and applies a callback function to each element. - * @param callback - The callback parameter is a function that takes two arguments: value and index. The value argument - * represents the value of the current node in the linked list, and the index argument represents the index of the - * current node in the linked list. - */ - forEach(callback: (value: E, index: number) => void): void { - let current = this.head; - let index = 0; - while (current) { - callback(current.value, index); - current = current.next; - index++; - } - } - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - */ - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - * - * The `map` function takes a callback function and applies it to each element in the SinglyLinkedList, returning a new - * SinglyLinkedList with the transformed values. - * @param callback - The callback parameter is a function that takes a value of type E (the type of values stored in - * the original SinglyLinkedList) and returns a value of type U (the type of values that will be stored in the mapped - * SinglyLinkedList). - * @returns The `map` function is returning a new instance of `SinglyLinkedList` that contains the mapped values. - */ - map(callback: (value: E) => U): SinglyLinkedList { - const mappedList = new SinglyLinkedList(); - let current = this.head; - while (current) { - mappedList.push(callback(current.value)); - current = current.next; - } - return mappedList; - } - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - */ - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - * - * The `filter` function iterates through a SinglyLinkedList and returns a new SinglyLinkedList containing only the - * elements that satisfy the given callback function. - * @param callback - The `callback` parameter is a function that takes a value of type `E` and returns a boolean value. - * It is used to determine whether a value should be included in the filtered list or not. - * @returns The filtered list, which is an instance of the SinglyLinkedList class. - */ - filter(callback: (value: E) => boolean): SinglyLinkedList { - const filteredList = new SinglyLinkedList(); - let current = this.head; - while (current) { - if (callback(current.value)) { - filteredList.push(current.value); - } - current = current.next; - } - return filteredList; - } - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - */ - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as they need to traverse the entire list to apply the callback or reduce the list. - * Space Complexity: O(n) - Linear space, as they create new nodes or arrays. - * - * The `reduce` function iterates over a linked list and applies a callback function to each element, accumulating a - * single value. - * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `value`. It is - * used to perform a specific operation on each element of the linked list. - * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting - * point for the reduction operation. - * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the - * elements in the linked list. - */ - reduce(callback: (accumulator: U, value: E) => U, initialValue: U): U { - let accumulator = initialValue; - let current = this.head; - while (current) { - accumulator = callback(accumulator, current.value); - current = current.next; - } - return accumulator; - } - /** * The function returns an iterator that iterates over the values of a linked list. */ @@ -781,4 +676,109 @@ export class SinglyLinkedList { current = current.next; } } + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(1) + * + * The `forEach` function iterates over each element in a linked list and applies a callback function to each element. + * @param callback - The callback parameter is a function that takes two arguments: value and index. The value argument + * represents the value of the current node in the linked list, and the index argument represents the index of the + * current node in the linked list. + */ + forEach(callback: (value: E, index: number, list: SinglyLinkedList) => void): void { + let index = 0; + for (const el of this) { + callback(el, index, this); + index++; + } + } + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `filter` function iterates through a SinglyLinkedList and returns a new SinglyLinkedList containing only the + * elements that satisfy the given callback function. + * @param callback - The `callback` parameter is a function that takes a value of type `E` and returns a boolean value. + * It is used to determine whether a value should be included in the filtered list or not. + * @returns The filtered list, which is an instance of the SinglyLinkedList class. + */ + filter(callback: (value: E, index: number, list: SinglyLinkedList) => boolean): SinglyLinkedList { + const filteredList = new SinglyLinkedList(); + let index = 0; + for (const current of this) { + if (callback(current, index, this)) { + filteredList.push(current); + } + index++; + } + return filteredList; + } + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `map` function takes a callback function and applies it to each element in the SinglyLinkedList, returning a new + * SinglyLinkedList with the transformed values. + * @param callback - The callback parameter is a function that takes a value of type E (the type of values stored in + * the original SinglyLinkedList) and returns a value of type T (the type of values that will be stored in the mapped + * SinglyLinkedList). + * @returns The `map` function is returning a new instance of `SinglyLinkedList` that contains the mapped values. + */ + map(callback: (value: E, index: number, list: SinglyLinkedList) => T): SinglyLinkedList { + const mappedList = new SinglyLinkedList(); + let index = 0; + for (const current of this) { + mappedList.push(callback(current, index, this)); + index++; + } + + return mappedList; + } + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n), where n is the number of elements in the linked list. + * Space Complexity: O(n) + * + * The `reduce` function iterates over a linked list and applies a callback function to each element, accumulating a + * single value. + * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `value`. It is + * used to perform a specific operation on each element of the linked list. + * @param {T} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting + * point for the reduction operation. + * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the + * elements in the linked list. + */ + reduce(callback: (accumulator: T, value: E, index: number, list: SinglyLinkedList) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const current of this) { + accumulator = callback(accumulator, current, index, this); + index++; + } + + return accumulator; + } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index b7cd79e..5ec2c2e 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -628,26 +628,6 @@ export class Deque { this._buckets = newBuckets; } - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `forEach` function iterates over each element in a deque and applies a callback function to - * each element. - * @param callback - The callback parameter is a function that will be called for each element in the - * deque. It takes three parameters: - */ - forEach(callback: (element: E, index: number, deque: Deque) => void) { - for (let i = 0; i < this.size; ++i) { - callback(this.getAt(i), i, this); - } - } - /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -674,101 +654,6 @@ export class Deque { return undefined; } - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `toArray` function converts the elements of a data structure into an array. - * @returns The `toArray()` method is returning an array of elements of type `E`. - */ - toArray(): E[] { - const arr: E[] = []; - for (let i = 0; i < this.size; ++i) { - arr.push(this.getAt(i)); - } - return arr; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `map` function takes a callback function and applies it to each element in the deque, - * returning a new deque with the results. - * @param callback - The `callback` parameter is a function that takes three arguments: - * @returns The `map` method is returning a new `Deque` object with the transformed elements. - */ - map(callback: (element: E, index: number, deque: Deque) => T): Deque { - const newDeque = new Deque([], this._bucketSize); - for (let i = 0; i < this.size; ++i) { - newDeque.push(callback(this.getAt(i), i, this)); - } - return newDeque; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `filter` function creates a new deque containing only the elements that satisfy the given - * predicate function. - * @param predicate - The `predicate` parameter is a function that takes three arguments: `element`, - * `index`, and `deque`. - * @returns The `filter` method is returning a new `Deque` object that contains only the elements - * that satisfy the given `predicate` function. - */ - filter(predicate: (element: E, index: number, deque: Deque) => boolean): Deque { - const newDeque = new Deque([], this._bucketSize); - for (let i = 0; i < this.size; ++i) { - const element = this.getAt(i); - if (predicate(element, i, this)) { - newDeque.push(element); - } - } - return newDeque; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `reduce` function iterates over the elements of a deque and applies a callback function to - * each element, accumulating a single value. - * @param callback - The `callback` parameter is a function that takes four arguments: - * @param {T} initialValue - The `initialValue` parameter is the initial value of the accumulator. It - * is the value that will be passed as the first argument to the `callback` function when reducing - * the elements of the deque. - * @returns the final value of the accumulator after iterating over all elements in the deque and - * applying the callback function to each element. - */ - reduce(callback: (accumulator: T, element: E, index: number, deque: Deque) => T, initialValue: T): T { - let accumulator = initialValue; - for (let i = 0; i < this.size; ++i) { - accumulator = callback(accumulator, this.getAt(i), i, this); - } - return accumulator; - } - /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -794,6 +679,26 @@ export class Deque { return -1; } + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `toArray` function converts the elements of a data structure into an array. + * @returns The `toArray()` method is returning an array of elements of type `E`. + */ + toArray(): E[] { + const arr: E[] = []; + for (let i = 0; i < this.size; ++i) { + arr.push(this.getAt(i)); + } + return arr; + } + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -812,6 +717,108 @@ export class Deque { } } + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `forEach` function iterates over each element in a deque and applies a callback function to + * each element. + * @param callback - The callback parameter is a function that will be called for each element in the + * deque. It takes three parameters: + */ + forEach(callback: (element: E, index: number, deque: this) => void) { + let index = 0; + for (const el of this) { + callback(el, index, this); + index++; + } + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new deque containing only the elements that satisfy the given + * predicate function. + * @param predicate - The `predicate` parameter is a function that takes three arguments: `element`, + * `index`, and `deque`. + * @returns The `filter` method is returning a new `Deque` object that contains only the elements + * that satisfy the given `predicate` function. + */ + filter(predicate: (element: E, index: number, deque: this) => boolean): Deque { + const newDeque = new Deque([], this._bucketSize); + let index = 0; + for (const el of this) { + if (predicate(el, index, this)) { + newDeque.push(el); + } + index++; + } + return newDeque; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `map` function takes a callback function and applies it to each element in the deque, + * returning a new deque with the results. + * @param callback - The `callback` parameter is a function that takes three arguments: + * @returns The `map` method is returning a new `Deque` object with the transformed elements. + */ + map(callback: (element: E, index: number, deque: this) => T): Deque { + const newDeque = new Deque([], this._bucketSize); + let index = 0; + for (const el of this) { + newDeque.push(callback(el, index, this)); + index++; + } + return newDeque; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `reduce` function iterates over the elements of a deque and applies a callback function to + * each element, accumulating a single value. + * @param callback - The `callback` parameter is a function that takes four arguments: + * @param {T} initialValue - The `initialValue` parameter is the initial value of the accumulator. It + * is the value that will be passed as the first argument to the `callback` function when reducing + * the elements of the deque. + * @returns the final value of the accumulator after iterating over all elements in the deque and + * applying the callback function to each element. + */ + reduce(callback: (accumulator: T, element: E, index: number, deque: this) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const el of this) { + accumulator = callback(accumulator, el, index, this); + index++; + } + return accumulator; + } + /** * Time Complexity: O(n) * Space Complexity: O(n) diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 035950a..74b0302 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -305,4 +305,88 @@ export class Queue { yield item; } } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `forEach` function iterates over each element in a deque and applies a callback function to + * each element. + * @param callback - The callback parameter is a function that will be called for each element in the + * deque. It takes three parameters: + */ + forEach(callback: (element: E, index: number, queue: this) => void) { + let index = 0; + for (const el of this) { + callback(el, index, this); + index++; + } + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new deque containing only the elements that satisfy the given + * predicate function. + * @param predicate - The `predicate` parameter is a function that takes three arguments: `element`, + * `index`, and `deque`. + * @returns The `filter` method is returning a new `Queue` object that contains only the elements + * that satisfy the given `predicate` function. + */ + filter(predicate: (element: E, index: number, queue: this) => boolean): Queue { + const newDeque = new Queue([]); + let index = 0; + for (const el of this) { + if (predicate(el, index, this)) { + newDeque.push(el); + } + index++; + } + return newDeque; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `map` function takes a callback function and applies it to each element in the deque, + * returning a new deque with the results. + * @param callback - The `callback` parameter is a function that takes three arguments: + * @returns The `map` method is returning a new `Queue` object with the transformed elements. + */ + map(callback: (element: E, index: number, queue: this) => T): Queue { + const newDeque = new Queue([]); + let index = 0; + for (const el of this) { + newDeque.push(callback(el, index, this)); + index++; + } + return newDeque; + } + + reduce(callback: (accumulator: T, element: E, index: number, queue: this) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const el of this) { + accumulator = callback(accumulator, el, index, this); + index++; + } + return accumulator; + } } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 20eb2f3..bfc4464 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -25,6 +25,14 @@ export class Stack { * Space Complexity: O(n), as it creates a new stack with the elements from the input array. */ + /** + * The size() function returns the number of elements in an array. + * @returns The size of the elements array. + */ + get size(): number { + return this.elements.length; + } + /** * Time Complexity: O(n), where n is the number of elements in the input array. Similar to the constructor, it requires iterating through each element. * Space Complexity: O(n), as it creates a new stack with the elements from the input array. @@ -46,14 +54,6 @@ export class Stack { return this.elements.length === 0; } - /** - * The size() function returns the number of elements in an array. - * @returns The size of the elements array. - */ - size(): number { - return this.elements.length; - } - /** * Time Complexity: O(1), as it only involves accessing the last element of the array. * Space Complexity: O(1), as it does not use any additional space. @@ -147,4 +147,60 @@ export class Stack { clone(): Stack { return new Stack(this.elements.slice()); } + + /** + * Custom iterator for the Stack class. + * @returns An iterator object. + */ + * [Symbol.iterator]() { + for (let i = this.elements.length - 1; i >= 0; i--) { + yield this.elements[i]; + } + } + + /** + * Applies a function to each element of the stack. + * @param {function(E): void} callback - A function to apply to each element. + */ + forEach(callback: (element: E, index: number, stack: this) => void): void { + let index = 0; + for (const el of this) { + callback(el, index, this); + index++; + } + } + + + filter(predicate: (element: E, index: number, stack: this) => boolean): Stack { + const newStack = new Stack(); + let index = 0; + for (const el of this) { + if (predicate(el, index, this)) { + newStack.push(el); + } + index++; + } + return newStack; + } + + + map(callback: (element: E, index: number, stack: this) => T): Stack { + const newStack = new Stack(); + let index = 0; + for (const el of this) { + newStack.push(callback(el, index, this)); + index++; + } + return newStack; + } + + reduce(callback: (accumulator: T, element: E, index: number, stack: this) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const el of this) { + accumulator = callback(accumulator, el, index, this); + index++; + } + return accumulator; + } } diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index ecf503c..e468bd3 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -324,6 +324,59 @@ export class Trie { return words; } + * [Symbol.iterator](): IterableIterator { + function* _dfs(node: TrieNode, path: string): IterableIterator { + if (node.isEnd) { + yield path; + } + for (const [char, childNode] of node.children) { + yield* _dfs(childNode, path + char); + } + } + + yield* _dfs(this.root, ''); + } + + forEach(callback: (word: string, index: number, trie: this) => void): void { + let index = 0; + for (const word of this) { + callback(word, index, this); + index++; + } + } + + filter(predicate: (word: string, index: number, trie: this) => boolean): string[] { + const results: string[] = []; + let index = 0; + for (const word of this) { + if (predicate(word, index, this)) { + results.push(word); + } + index++; + } + return results; + } + + map(callback: (word: string, index: number, trie: this) => string): Trie { + const newTrie = new Trie(); + let index = 0; + for (const word of this) { + newTrie.add(callback(word, index, this)); + index++; + } + return newTrie; + } + + reduce(callback: (accumulator: T, word: string, index: number, trie: this) => T, initialValue: T): T { + let accumulator = initialValue; + let index = 0; + for (const word of this) { + accumulator = callback(accumulator, word, index, this); + index++; + } + return accumulator; + } + /** * Time Complexity: O(M), where M is the length of the input string. * Space Complexity: O(1) - Constant space. diff --git a/test/integration/conversion.test.ts b/test/integration/conversion.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/test/performance/data-structures/heap/heap.test.ts b/test/performance/data-structures/heap/heap.test.ts index dff3afa..1a2942b 100644 --- a/test/performance/data-structures/heap/heap.test.ts +++ b/test/performance/data-structures/heap/heap.test.ts @@ -3,20 +3,29 @@ import * as Benchmark from 'benchmark'; import { magnitude } from '../../../utils'; const suite = new Benchmark.Suite(); -const { TEN_THOUSAND } = magnitude; +const { HUNDRED_THOUSAND, TEN_THOUSAND } = magnitude; suite - .add(`${TEN_THOUSAND.toLocaleString()} add & pop`, () => { + .add(`${HUNDRED_THOUSAND.toLocaleString()} add & pop`, () => { const heap = new Heap({ comparator: (a, b) => b - a }); - for (let i = 0; i < TEN_THOUSAND; i++) { + for (let i = 0; i < HUNDRED_THOUSAND; i++) { heap.add(i); } - for (let i = 0; i < TEN_THOUSAND; i++) { + for (let i = 0; i < HUNDRED_THOUSAND; i++) { heap.pop(); } }) + .add(`${HUNDRED_THOUSAND.toLocaleString()} add & dfs`, () => { + const heap = new Heap({ comparator: (a, b) => b - a }); + + for (let i = 0; i < HUNDRED_THOUSAND; i++) { + heap.add(i); + } + + heap.dfs(); + }) .add(`${TEN_THOUSAND.toLocaleString()} fib add & pop`, () => { const fbHeap = new FibonacciHeap(); for (let i = 1; i <= TEN_THOUSAND; i++) { diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index f1b156d..2447bd8 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -8,7 +8,7 @@ describe('HashNode', () => { expect(hashNode.key).toBe(key); expect(hashNode.value).toBe(value); - expect(hashNode.next).toBe(null); + expect(hashNode.next).toBe(undefined); }); }); @@ -16,7 +16,7 @@ describe('HashTable', () => { it('should initialize with default capacity', () => { const hashTable = new HashTable(); expect(hashTable.capacity).toBe(16); - expect(hashTable.buckets).toEqual(new Array(16).fill(null)); + expect(hashTable.buckets).toEqual(new Array(16).fill(undefined)); expect(hashTable.hashFn('a')).toBe(6); expect(hashTable.capacity).toBe(16); expect(hashTable.size).toBe(0); @@ -184,3 +184,59 @@ describe('HashTable performance', function () { } }); }); + + +describe('HashTable methods', () => { + let hashTable: HashTable; + + beforeEach(() => { + hashTable = new HashTable(); + for (let i = 0; i < 10; i++) { + hashTable.set(`key${i}`, `value${i}`); + } + }); + + test('should retrieve correct values with get method', () => { + for (let i = 0; i < 10; i++) { + expect(hashTable.get(`key${i}`)).toBe(`value${i}`); + } + }); + + // test('forEach should apply a function to each key-value pair', () => { + // const mockCallback = jest.fn(); + // hashTable.forEach(mockCallback); + // + // expect(mockCallback.mock.calls.length).toBe(10); + // for (let i = 0; i < 10; i++) { + // // Check whether each key-value pair has been called before, regardless of the order + // const call = mockCallback.mock.calls.find(call => call[1] === `value${i}`); + // expect(call).toBeTruthy(); + // expect(call[0]).toBe(`key${i}`); + // } + // }); + + + test('filter should return a new HashTable with elements that satisfy the condition', () => { + const filtered = hashTable.filter(([key]) => key.endsWith('1') || key.endsWith('3')); + + expect(filtered.size).toBe(2); + expect(filtered.get('key1')).toBe('value1'); + expect(filtered.get('key3')).toBe('value3'); + }); + + test('map should return a new HashTable with mapped values', () => { + const mapped = hashTable.map(([, value]) => value.toUpperCase()); + + for (let i = 0; i < 10; i++) { + expect(mapped.get(`key${i}`)).toBe(`value${i}`.toUpperCase()); + } + }); + + test('reduce should accumulate values based on the reducer function', () => { + const result = hashTable.reduce((acc, [, value]) => `${acc}-${value}`, ''); + + expect(result).toBe('-value5-value7-value3-value4-value6-value0-value2-value8-value1-value9'); + }); + +}); + diff --git a/test/unit/data-structures/heap/min-heap.test.ts b/test/unit/data-structures/heap/min-heap.test.ts index 35f507b..cdd8960 100644 --- a/test/unit/data-structures/heap/min-heap.test.ts +++ b/test/unit/data-structures/heap/min-heap.test.ts @@ -49,4 +49,52 @@ describe('MinHeap', () => { minHeap.poll(); expect(minHeap.isEmpty()).toBe(true); }); + + + const n = 100000; + + it('should push & dfs', () => { + for (let i = 0; i < n; i++) { + minHeap.push(i); + } + expect(minHeap.dfs()[0]).toBe(0) + expect(minHeap.dfs()[999]).toBe(4126) + }); + +}); + +describe('Heap iterative methods', () => { + let heap: MinHeap; + + beforeEach(() => { + heap = new MinHeap(); + for (let i = 1; i <= 10; i++) { + heap.add(i * 10); // Add 10, 20, ..., 100 + } + }); + + test('Heap is iterable', () => { + expect([...heap]).toEqual([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]); + }); + + test('forEach method calls a function for each element', () => { + const mockCallback = jest.fn(); + heap.forEach(mockCallback); + expect(mockCallback.mock.calls.length).toBe(10); + }); + + test('filter method returns filtered elements', () => { + const result = heap.filter(x => x > 50); + expect([...result]).toEqual([60, 70, 80, 90, 100]); + }); + + test('map method correctly maps elements', () => { + const result = heap.map(x => x / 10, (a: number, b: number) => a - b); + expect([...result]).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + test('reduce method correctly reduces elements', () => { + const result = heap.reduce((acc, curr) => acc + curr, 0); + expect(result).toBe(550); // 10+20+...+100 = 550 + }); }); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index 73d5323..21c3877 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -166,7 +166,7 @@ describe('DoublyLinkedList Operation Test', () => { list.reverse(); expect(list.toArray()).toEqual([3, 2, 1]); - expect(list.toArrayBackward()).toEqual([1, 2, 3]); + expect(list.toReversedArray()).toEqual([1, 2, 3]); }); it('should map elements using a callback function', () => { @@ -268,7 +268,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const reversedArray = list.toArrayBackward(); + const reversedArray = list.toReversedArray(); expect(reversedArray).toEqual([3, 2, 1]); }); diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 5c81df9..8da24c4 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -205,3 +205,40 @@ describe('Queue Performance Test', () => { expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); }); }); + + +describe('Queue iterative methods', () => { + let queue: Queue; + + beforeEach(() => { + queue = new Queue(); + for (let i = 0; i < 10; i++) { + queue.enqueue(i); + } + }); + + test('iterator should provide access to all elements', () => { + const elements = []; + for (const item of queue) { + elements.push(item); + } + expect(elements).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + }); + + test('forEach should apply the callback to each element', () => { + const elements: number[] = []; + queue.forEach((element) => elements.push(element * 2)); + expect(elements).toEqual([0, 2, 4, 6, 8, 10, 12, 14, 16, 18]); + }); + + test('filter should return a new queue with only the elements that satisfy the predicate', () => { + const filteredQueue = queue.filter(element => element % 2 === 0); + expect([...filteredQueue]).toEqual([0, 2, 4, 6, 8]); + }); + + test('map should return a new queue with the transformed elements', () => { + const mappedQueue = queue.map(element => element * 2); + expect([...mappedQueue]).toEqual([0, 2, 4, 6, 8, 10, 12, 14, 16, 18]); + }); + +}); \ No newline at end of file diff --git a/test/unit/data-structures/stack/stack.test.ts b/test/unit/data-structures/stack/stack.test.ts index 4f9c45a..8ee443d 100644 --- a/test/unit/data-structures/stack/stack.test.ts +++ b/test/unit/data-structures/stack/stack.test.ts @@ -15,7 +15,7 @@ describe('Stack', () => { stack.push(1); stack.push(2); stack.push(3); - expect(stack.size()).toBe(3); + expect(stack.size).toBe(3); }); it('should peek at the top element without removing it', () => { @@ -23,7 +23,7 @@ describe('Stack', () => { stack.push(2); stack.push(3); expect(stack.peek()).toBe(3); - expect(stack.size()).toBe(3); + expect(stack.size).toBe(3); }); it('should pop elements from the stack', () => { @@ -32,7 +32,7 @@ describe('Stack', () => { stack.push(3); const poppedElement = stack.pop(); expect(poppedElement).toBe(3); - expect(stack.size()).toBe(2); + expect(stack.size).toBe(2); }); it('should return null when popping from an empty stack', () => { @@ -53,7 +53,7 @@ describe('Stack', () => { stack.push(2); stack.push(3); stack.clear(); - expect(stack.size()).toBe(0); + expect(stack.size).toBe(0); expect(stack.isEmpty()).toBe(true); }); @@ -61,7 +61,57 @@ describe('Stack', () => { stack.push(1); stack.push(2); const clonedStack = stack.clone(); - expect(clonedStack.size()).toBe(2); + expect(clonedStack.size).toBe(2); expect(clonedStack.pop()).toBe(2); }); }); + + +describe('Stack iterative methods', () => { + let stack: Stack; // Declare a Stack instance + + beforeEach(() => { + stack = new Stack(); // Create a new Stack instance before each test + stack.push(1); + stack.push(2); + stack.push(3); + }); + + test('should iterate through the stack', () => { + const result: number[] = []; + for (const element of stack) { + result.push(element); + } + + expect(result).toEqual([3, 2, 1]); // iteration should start from the top of the stack + }); + + test('should apply forEach to the stack', () => { + const result: number[] = []; + stack.forEach((element) => { + result.push(element); + }); + + expect(result).toEqual([3, 2, 1]); + }); + + test('should filter elements in the stack', () => { + const filteredStack = stack.filter((element) => element > 1); + + expect(filteredStack.size).toBe(2); + expect([...filteredStack]).toEqual([2, 3]); + }); + + test('should map elements in the stack', () => { + const mappedStack = stack.map((element) => element * 2); + + expect(mappedStack.size).toBe(3); + expect([...mappedStack]).toEqual([2, 4, 6]); + }); + + test('should reduce elements in the stack', () => { + const sum = stack.reduce((accumulator, element) => accumulator + element, 0); + + expect(sum).toBe(6); + }); +}); diff --git a/test/unit/data-structures/trie/trie.test.ts b/test/unit/data-structures/trie/trie.test.ts index 99089c0..5b1afcd 100644 --- a/test/unit/data-structures/trie/trie.test.ts +++ b/test/unit/data-structures/trie/trie.test.ts @@ -823,3 +823,36 @@ describe('Trie operations', () => { expect(trie.getHeight()).toBe(6); // Assuming 'apple' and 'banana' are the longest words. }); }); + +describe('Trie class', () => { + let trie: Trie; + beforeEach(() => { + trie = new Trie(['apple', 'app', 'banana', 'band', 'bandana']); + }); + + test('[Symbol.iterator] should iterate over all words', () => { + const words = [...trie]; + expect(words).toEqual(['app', 'apple', 'banana', 'band', 'bandana']); + }); + + test('forEach should execute a callback for each word', () => { + const mockCallback = jest.fn(); + trie.forEach(mockCallback); + expect(mockCallback).toHaveBeenCalledTimes(5); + }); + + test('filter should return words that satisfy the predicate', () => { + const filteredWords = trie.filter(word => word.startsWith('ba')); + expect(filteredWords).toEqual(['banana', 'band', 'bandana']); + }); + + test('map should apply a function to each word', () => { + const mappedWords = trie.map(word => word.length.toString()); + expect([...mappedWords]).toEqual(['3', '5', '6', '4', '7']); + }); + + test('reduce should reduce the words to a single value', () => { + const concatenatedWords = trie.reduce((acc, word) => acc + word, ''); + expect(concatenatedWords).toEqual('appapplebananabandbandana'); + }); +});