diff --git a/src/data-structures/base/iterable-element-base.ts b/src/data-structures/base/iterable-element-base.ts index a12a367..80556cd 100644 --- a/src/data-structures/base/iterable-element-base.ts +++ b/src/data-structures/base/iterable-element-base.ts @@ -1,6 +1,6 @@ import { ElementCallback, IterableElementBaseOptions, ReduceElementCallback } from '../../types'; -export abstract class IterableElementBase { +export abstract class IterableElementBase { /** * The protected constructor initializes the options for the IterableElementBase class, including the * toElementFn function. @@ -14,17 +14,8 @@ export abstract class IterableElementBase { } } - // abstract get size(): number; - protected _toElementFn?: (rawElement: R) => E; - /** - * The function returns the _toElementFn property, which is a function that converts a raw element to - * a specific type. - * @returns The function `get toElementFn()` is returning either a function that takes a raw element - * `rawElement` of type `R` and returns an element `E`, or `undefined` if no function is assigned to - * `_toElementFn`. - */ get toElementFn(): ((rawElement: R) => E) | undefined { return this._toElementFn; } @@ -68,7 +59,7 @@ export abstract class IterableElementBase { * @returns The `every` method is returning a boolean value. It returns `true` if every element in * the array satisfies the provided predicate function, and `false` otherwise. */ - every(predicate: ElementCallback, thisArg?: any): boolean { + every(predicate: ElementCallback, thisArg?: any): boolean { let index = 0; for (const item of this) { if (!predicate.call(thisArg, item, index++, this)) { @@ -92,7 +83,7 @@ export abstract class IterableElementBase { * @returns a boolean value. It returns true if the predicate function returns true for any element * in the collection, and false otherwise. */ - some(predicate: ElementCallback, thisArg?: any): boolean { + some(predicate: ElementCallback, thisArg?: any): boolean { let index = 0; for (const item of this) { if (predicate.call(thisArg, item, index++, this)) { @@ -115,20 +106,23 @@ export abstract class IterableElementBase { * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will * be passed as the `this` value to the `callbackfn` function. If `thisArg */ - forEach(callbackfn: ElementCallback, thisArg?: any): void { + forEach(callbackfn: ElementCallback, thisArg?: any): void { let index = 0; for (const item of this) { callbackfn.call(thisArg, item, index++, this); } } + find(predicate: ElementCallback, thisArg?: any): S | undefined; + find(predicate: ElementCallback, thisArg?: any): E | undefined; + /** * Time Complexity: O(n) * Space Complexity: O(1) * * The `find` function iterates over the elements of an array-like object and returns the first * element that satisfies the provided callback function. - * @param callbackfn - The callbackfn parameter is a function that will be called for each element in + * @param predicate - The predicate parameter is a function that will be called for each element in * the array. It takes three arguments: the current element being processed, the index of the current * element, and the array itself. The function should return a boolean value indicating whether the * current element matches the desired condition. @@ -138,10 +132,10 @@ export abstract class IterableElementBase { * @returns The `find` method returns the first element in the array that satisfies the provided * callback function. If no element satisfies the callback function, `undefined` is returned. */ - find(callbackfn: ElementCallback, thisArg?: any): E | undefined { + find(predicate: ElementCallback, thisArg?: any): E | undefined { let index = 0; for (const item of this) { - if (callbackfn.call(thisArg, item, index++, this)) return item; + if (predicate.call(thisArg, item, index++, this)) return item; } return; @@ -164,6 +158,10 @@ export abstract class IterableElementBase { return false; } + reduce(callbackfn: ReduceElementCallback): E; + reduce(callbackfn: ReduceElementCallback, initialValue: E): E; + reduce(callbackfn: ReduceElementCallback, initialValue: U): U; + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -177,15 +175,26 @@ export abstract class IterableElementBase { * @returns The `reduce` method is returning the final value of the accumulator after iterating over * all the elements in the array and applying the callback function to each element. */ - reduce(callbackfn: ReduceElementCallback, initialValue: U): U { - let accumulator = initialValue; + reduce(callbackfn: ReduceElementCallback, initialValue?: U): U { + let accumulator = initialValue ?? (0 as U); let index = 0; for (const item of this) { - accumulator = callbackfn(accumulator, item as E, index++, this); + accumulator = callbackfn(accumulator, item, index++, this); } return accumulator; } + /** + * Time Complexity: O(n) + * 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[] { + return [...this]; + } + /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -210,7 +219,7 @@ export abstract class IterableElementBase { abstract clear(): void; - abstract clone(): C; + abstract clone(): IterableElementBase; abstract map(...args: any[]): any; diff --git a/src/data-structures/base/linear-base.ts b/src/data-structures/base/linear-base.ts new file mode 100644 index 0000000..3ec146e --- /dev/null +++ b/src/data-structures/base/linear-base.ts @@ -0,0 +1,571 @@ +import { ElementCallback, LinearBaseOptions, ReduceLinearCallback } from '../../types'; +import { IterableElementBase } from './iterable-element-base'; + +export abstract class LinearBase extends IterableElementBase { + protected constructor(options?: LinearBaseOptions) { + super(options); + if (options) { + const { maxLen } = options; + if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen; + } + } + + abstract get length(): number; + + protected _maxLen: number = -1; + + get maxLen() { + return this._maxLen; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function indexOf searches for a specified element starting from a given index in an array-like + * object and returns the index of the first occurrence, or -1 if not found. + * @param {E} searchElement - The `searchElement` parameter in the `indexOf` function represents the + * element that you want to find within the array. The function will search for this element starting + * from the `fromIndex` (if provided) up to the end of the array. If the `searchElement` is found + * within the + * @param {number} [fromIndex=0] - The `fromIndex` parameter in the `indexOf` function represents the + * index at which to start searching for the `searchElement` within the array. If provided, the + * search will begin at this index and continue to the end of the array. If `fromIndex` is not + * specified, the default + * @returns The `indexOf` method is returning the index of the `searchElement` if it is found in the + * array starting from the `fromIndex`. If the `searchElement` is not found, it returns -1. + */ + indexOf(searchElement: E, fromIndex: number = 0): number { + // Boundary checks and adjustments + if (this.length === 0) return -1; + if (fromIndex < 0) fromIndex = this.length + fromIndex; + if (fromIndex < 0) fromIndex = 0; + + // Iterating from the specified index to the end + for (let i = fromIndex; i < this.length; i++) { + const element = this.at(i); + if (element === searchElement) return i; + } + + return -1; // Not found + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function `lastIndexOf` in TypeScript returns the index of the last occurrence of a specified + * element in an array. + * @param {E} searchElement - The `searchElement` parameter is the element that you want to find the + * last index of within the array. The `lastIndexOf` method will search the array starting from the + * `fromIndex` (or the end of the array if not specified) and return the index of the last occurrence + * of the + * @param {number} fromIndex - The `fromIndex` parameter in the `lastIndexOf` method specifies the + * index at which to start searching for the `searchElement` in the array. By default, it starts + * searching from the last element of the array (`this.length - 1`). If a specific `fromIndex` is + * provided + * @returns The last index of the `searchElement` in the array is being returned. If the + * `searchElement` is not found in the array, -1 is returned. + */ + lastIndexOf(searchElement: E, fromIndex: number = this.length - 1): number { + if (this.length === 0) return -1; + if (fromIndex >= this.length) fromIndex = this.length - 1; + if (fromIndex < 0) fromIndex = this.length + fromIndex; + + for (let i = fromIndex; i >= 0; i--) { + const element = this.at(i); + if (element === searchElement) return i; + } + + return -1; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `findIndex` function iterates over an array and returns the index of the first element that + * satisfies the provided predicate function. + * @param predicate - The `predicate` parameter in the `findIndex` function is a callback function + * that takes three arguments: `item`, `index`, and the array `this`. It should return a boolean + * value indicating whether the current element satisfies the condition being checked for. + * @param {any} [thisArg] - The `thisArg` parameter in the `findIndex` function is an optional + * parameter that specifies the value to use as `this` when executing the `predicate` function. If + * provided, the `predicate` function will be called with `thisArg` as its `this` value. If ` + * @returns The `findIndex` method is returning the index of the first element in the array that + * satisfies the provided predicate function. If no such element is found, it returns -1. + */ + findIndex(predicate: ElementCallback, thisArg?: any): number { + for (let i = 0; i < this.length; i++) { + const item = this.at(i); + if (item !== undefined && predicate.call(thisArg, item, i, this)) return i; + } + return -1; + } + + concat(...items: LinearBase[]): this; + + /** + * Time Complexity: O(n + m) + * Space Complexity: O(n + m) + * + * The `concat` function in TypeScript concatenates multiple items into a new list, handling both + * individual elements and instances of `LinearBase`. + * @param {(E | LinearBase)[]} items - The `concat` method takes in an array of items, where + * each item can be either of type `E` or an instance of `LinearBase`. + * @returns The `concat` method is returning a new instance of the class that it belongs to, with the + * items passed as arguments concatenated to it. + */ + concat(...items: (E | LinearBase)[]): this { + const newList = this.clone(); + + for (const item of items) { + if (item instanceof LinearBase) { + newList.pushMany(item); + } else { + newList.push(item); + } + } + + return newList; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `sort` function in TypeScript sorts the elements of a collection using a specified comparison + * function. + * @param [compareFn] - The `compareFn` parameter is a function that defines the sort order. It takes + * two elements `a` and `b` as input and returns a number indicating their relative order. If the + * returned value is negative, `a` comes before `b`. If the returned value is positive, ` + * @returns The `sort` method is returning the instance of the object on which it is called (this), + * after sorting the elements based on the provided comparison function (compareFn). + */ + sort(compareFn?: (a: E, b: E) => number): this { + const arr = this.toArray(); + arr.sort(compareFn); + this.clear(); + for (const item of arr) this.push(item); + return this; + } + + /** + * Time Complexity: O(n + m) + * Space Complexity: O(m) + * + * The `splice` function in TypeScript removes elements from an array and optionally inserts new + * elements at the specified index. + * @param {number} start - The `start` parameter in the `splice` method indicates the index at which + * to start modifying the array. If `start` is a negative number, it will count from the end of the + * array. + * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the + * number of elements to remove from the array starting at the specified `start` index. If + * `deleteCount` is not provided or is 0, no elements are removed, and only new elements are inserted + * at the `start` + * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that + * will be inserted into the array at the specified `start` index. These elements can be of any type + * and you can pass multiple elements separated by commas. The `splice` method will insert these + * items into the array at the + * @returns The `splice` method returns a list of elements that were removed from the original list + * during the operation. + */ + splice(start: number, deleteCount: number = 0, ...items: E[]): this { + start = start < 0 ? this.length + start : start; + if (start < 0) start = 0; + if (start > this.length) start = this.length; + + const removedList = this._createInstance({ toElementFn: this._toElementFn }); + + // Move to starting position + let currentNode = this.at(start); + let currentIndex = start; + + // Delete elements + for (let i = 0; i < deleteCount && currentNode !== undefined; i++) { + removedList.push(currentNode); + this.delete(currentNode); + currentNode = this.at(currentIndex); // Update node reference + } + + // Insert new element + for (const item of items) { + this.addAt(currentIndex, item); + currentIndex++; + } + + return removedList; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `join` function in TypeScript returns a string by joining the elements of an array with a + * specified separator. + * @param {string} [separator=,] - The `separator` parameter is a string that specifies the character + * or characters that will be used to separate each element when joining them into a single string. + * By default, the separator is set to a comma (`,`), but you can provide a different separator if + * needed. + * @returns The `join` method is being returned, which takes an optional `separator` parameter + * (defaulting to a comma) and returns a string created by joining all elements of the array after + * converting it to an array. + */ + join(separator: string = ','): string { + return this.toArray().join(separator); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The function `toReversedArray` takes an array and returns a new array with its elements in reverse + * order. + * @returns The `toReversedArray()` function returns an array of elements of type `E` in reverse + * order. + */ + toReversedArray(): E[] { + const array: E[] = []; + for (let i = this.length - 1; i >= 0; i--) { + array.push(this.at(i)!); + } + return array; + } + + reduceRight(callbackfn: ReduceLinearCallback): E; + + reduceRight(callbackfn: ReduceLinearCallback, initialValue: E): E; + + reduceRight(callbackfn: ReduceLinearCallback, initialValue: U): U; + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `reduceRight` function in TypeScript iterates over an array from right to left and applies a + * callback function to each element, accumulating a single result. + * @param callbackfn - The `callbackfn` parameter in the `reduceRight` method is a function that will + * be called on each element in the array from right to left. It takes four arguments: + * @param {U} [initialValue] - The `initialValue` parameter in the `reduceRight` method is an + * optional parameter that specifies the initial value of the accumulator. If provided, the + * `accumulator` will start with this initial value before iterating over the elements of the array. + * If `initialValue` is not provided, the accumulator will + * @returns The `reduceRight` method is returning the final accumulated value after applying the + * callback function to each element in the array from right to left. + */ + reduceRight(callbackfn: ReduceLinearCallback, initialValue?: U): U { + let accumulator = initialValue ?? (0 as U); + for (let i = this.length - 1; i >= 0; i--) { + accumulator = callbackfn(accumulator, this.at(i)!, i, this); + } + return accumulator; + } + + /** + * Time Complexity: O(m) + * Space Complexity: O(m) + * + * The `slice` function in TypeScript creates a new instance by extracting a portion of elements from + * the original instance based on the specified start and end indices. + * @param {number} [start=0] - The `start` parameter in the `slice` method represents the index at + * which to begin extracting elements from an array-like object. If no `start` parameter is provided, + * the default value is 0, meaning the extraction will start from the beginning of the array. + * @param {number} end - The `end` parameter in the `slice` method represents the index at which to + * end the slicing. By default, if no `end` parameter is provided, it will slice until the end of the + * array (i.e., `this.length`). + * @returns The `slice` method is returning a new instance of the object with elements sliced from + * the specified start index (default is 0) to the specified end index (default is the length of the + * object). + */ + slice(start: number = 0, end: number = this.length): this { + start = start < 0 ? this.length + start : start; + end = end < 0 ? this.length + end : end; + + const newList = this._createInstance(); + for (let i = start; i < end; i++) { + newList.push(this.at(i)!); + } + return newList; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `fill` function in TypeScript fills a specified range in an array-like object with a given + * value. + * @param {E} value - The `value` parameter in the `fill` method represents the element that will be + * used to fill the specified range in the array. + * @param [start=0] - The `start` parameter specifies the index at which to start filling the array + * with the specified value. If not provided, it defaults to 0, indicating the beginning of the + * array. + * @param end - The `end` parameter in the `fill` function represents the index at which the filling + * of values should stop. It specifies the end of the range within the array where the `value` should + * be filled. + * @returns The `fill` method is returning the modified object (`this`) after filling the specified + * range with the provided value. + */ + fill(value: E, start = 0, end = this.length): this { + // Handling negative indexes + start = start < 0 ? this.length + start : start; + end = end < 0 ? this.length + end : end; + + // Boundary processing + if (start < 0) start = 0; + if (end > this.length) end = this.length; + if (start >= end) return this; + + // Iterate through the specified range and fill in the values + for (let i = start; i < end; i++) { + this.setAt(i, value); + } + + return this; + } + + abstract setAt(index: number, value: E): boolean; + + abstract override clone(): this; + + abstract reverse(): this; + + abstract push(elementOrNode: E | NODE): boolean; + + abstract pushMany(elements: Iterable | Iterable | Iterable): boolean[]; + + abstract delete(elementOrNode: E | NODE | undefined): boolean; + + abstract at(index: number): E | undefined; + + abstract deleteAt(pos: number): boolean; + + abstract addAt(index: number, newElementOrNode: E | NODE): boolean; + + protected abstract _createInstance(options?: LinearBaseOptions): this; + + protected abstract _getReverseIterator(...args: any[]): IterableIterator; +} + +export abstract class LinearLinkedBase extends LinearBase { + protected constructor(options?: LinearBaseOptions) { + super(options); + if (options) { + const { maxLen } = options; + if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen; + } + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function overrides the indexOf method to improve performance by searching for an element in a + * custom array implementation starting from a specified index. + * @param {E} searchElement - The `searchElement` parameter is the element that you are searching for + * within the array. The `indexOf` method will return the index of the first occurrence of this + * element within the array. + * @param {number} [fromIndex=0] - The `fromIndex` parameter in the `indexOf` method specifies the + * index in the array at which to start the search for the `searchElement`. If provided, the search + * will begin at the specified index and continue to the end of the array. If not provided, the + * search will start at index + * @returns The `indexOf` method is returning the index of the `searchElement` if it is found in the + * array starting from the `fromIndex`. If the `searchElement` is not found, it returns -1. + */ + override indexOf(searchElement: E, fromIndex: number = 0): number { + // In order to improve performance, it is best to override this method in the subclass of the array implementation + const iterator = this._getIterator(); + let current = iterator.next(); + + let index = 0; + while (index < fromIndex) { + current = iterator.next(); + index++; + } + + while (!current.done) { + if (current.value === searchElement) return index; + current = iterator.next(); + index++; + } + + return -1; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function overrides the lastIndexOf method in TypeScript to improve performance by searching + * for an element in reverse order starting from a specified index. + * @param {E} searchElement - The `searchElement` parameter is the element that you want to find + * within the array. The `lastIndexOf` method searches the array for this element starting from the + * end of the array (or from the specified `fromIndex` if provided) and returns the index of the last + * occurrence of the element + * @param {number} fromIndex - The `fromIndex` parameter in the `lastIndexOf` method specifies the + * index at which to start searching for the `searchElement` in the array. If provided, the search + * will begin at this index and move towards the beginning of the array. If not provided, the search + * will start at the + * @returns The `lastIndexOf` method is being overridden to search for the `searchElement` starting + * from the specified `fromIndex` (defaulting to the end of the array). It iterates over the array in + * reverse order using a custom iterator `_getReverseIterator` and returns the index of the last + * occurrence of the `searchElement` if found, or -1 if not found. + */ + override lastIndexOf(searchElement: E, fromIndex: number = this.length - 1): number { + // In order to improve performance, it is best to override this method in the subclass of the array implementation + const iterator = this._getReverseIterator(); + let current = iterator.next(); + + let index = this.length - 1; + while (index > fromIndex) { + current = iterator.next(); + index--; + } + + while (!current.done) { + if (current.value === searchElement) return index; + current = iterator.next(); + index--; + } + + return -1; + } + + override concat(...items: LinearBase[]): this; + + /** + * Time Complexity: O(n + m) + * Space Complexity: O(n + m) + * + * The `concat` function in TypeScript overrides the default behavior to concatenate items into a new + * list, handling both individual elements and instances of `LinearBase`. + * @param {(E | LinearBase)[]} items - The `concat` method you provided takes in a variable + * number of arguments of type `E` or `LinearBase`. The method concatenates these items to the + * current list and returns a new list with the concatenated items. + * @returns The `concat` method is returning a new instance of the class that it belongs to, with the + * items passed as arguments concatenated to it. + */ + override concat(...items: (E | LinearBase)[]): this { + const newList = this.clone(); + + for (const item of items) { + if (item instanceof LinearBase) { + newList.pushMany(item); + } else { + newList.push(item); + } + } + + return newList; + } + + /** + * Time Complexity: O(n + m) + * Space Complexity: O(m) + * + * The function overrides the splice method to handle deletion and insertion of elements in a data + * structure while returning the removed elements. + * @param {number} start - The `start` parameter in the `splice` method indicates the index at which + * to start modifying the array. + * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the + * number of elements to remove from the array starting at the specified `start` index. If + * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new + * elements can still be inserted at + * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that + * will be inserted into the array at the specified `start` index. These elements can be of any type + * and there can be multiple elements passed as arguments to be inserted into the array. + * @returns The `splice` method is returning a new instance of the data structure that was modified + * by removing elements specified by the `start` and `deleteCount` parameters, and inserting new + * elements provided in the `items` array. + */ + override splice(start: number, deleteCount: number = 0, ...items: E[]): this { + start = start < 0 ? this.length + start : start; + if (start < 0) start = 0; + if (start > this.length) start = this.length; + + const removedList = this._createInstance({ toElementFn: this._toElementFn }); + + // Move to starting position + let currentNode = this.at(start); + let currentIndex = start; + + // Delete elements + for (let i = 0; i < deleteCount && currentNode !== undefined; i++) { + removedList.push(currentNode); + this.delete(currentNode); + currentNode = this.at(currentIndex); // Update node reference + } + + // Insert new element + for (const item of items) { + this.addAt(currentIndex, item); + currentIndex++; + } + + return removedList; + } + + override reduceRight(callbackfn: ReduceLinearCallback): E; + + override reduceRight(callbackfn: ReduceLinearCallback, initialValue: E): E; + + override reduceRight(callbackfn: ReduceLinearCallback, initialValue: U): U; + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function `reduceRight` iterates over an array in reverse order and applies a callback function + * to each element, accumulating a single result. + * @param callbackfn - The `callbackfn` parameter is a function that will be called on each element + * of the array from right to left. It takes four arguments: + * @param {U} [initialValue] - The `initialValue` parameter is an optional value that is used as the + * initial accumulator value in the reduce operation. If provided, the reduce operation starts with + * this initial value and iterates over the elements of the array, applying the callback function to + * each element and the current accumulator value. If `initial + * @returns The `reduceRight` method is returning the final accumulated value after applying the + * callback function to each element in the array from right to left. + */ + override reduceRight(callbackfn: ReduceLinearCallback, initialValue?: U): U { + let accumulator = initialValue ?? (0 as U); + let index = this.length - 1; + for (const item of this._getReverseIterator()) { + accumulator = callbackfn(accumulator, item, index--, this); + } + return accumulator; + } + + /** + * Time Complexity: O(m) + * Space Complexity: O(m) + * + * The `slice` method is overridden to improve performance by creating a new instance and iterating + * through the array to extract a subset based on the specified start and end indices. + * @param {number} [start=0] - The `start` parameter in the `slice` method specifies the index at + * which to begin extracting elements from the array. If no `start` parameter is provided, the + * default value is 0, indicating that extraction should start from the beginning of the array. + * @param {number} end - The `end` parameter in the `slice` method represents the index at which to + * end the slicing of the array. If not provided, it defaults to the length of the array. + * @returns The `slice` method is returning a new instance of the array implementation with elements + * sliced from the original array based on the `start` and `end` parameters. + */ + override slice(start: number = 0, end: number = this.length): this { + // In order to improve performance, it is best to override this method in the subclass of the array implementation + start = start < 0 ? this.length + start : start; + end = end < 0 ? this.length + end : end; + + const newList = this._createInstance(); + const iterator = this._getIterator(); + let current = iterator.next(); + let c = 0; + while (c < start) { + current = iterator.next(); + c++; + } + for (let i = start; i < end; i++) { + newList.push(current.value); + current = iterator.next(); + } + + return newList; + } +} diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index c52f88f..7a4b146 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -185,7 +185,7 @@ import { IterableElementBase } from '../base'; * ]); * console.log(scheduleTasks(tasks, 2)); // expectedMap */ -export class Heap extends IterableElementBase> { +export class Heap extends IterableElementBase { /** * The constructor initializes a heap data structure with optional elements and options. * @param elements - The `elements` parameter is an iterable object that contains the initial @@ -416,17 +416,6 @@ export class Heap extends IterableElementBase return result; } - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * Convert the heap to an array. - * @returns An array containing the elements of the heap. - */ - toArray(): E[] { - return [...this.elements]; - } - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -483,7 +472,7 @@ export class Heap extends IterableElementBase * @returns The `filter` method is returning a new `Heap` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - filter(callback: ElementCallback>, thisArg?: any): Heap { + filter(callback: ElementCallback, thisArg?: any): Heap { const filteredList = new Heap([], { toElementFn: this.toElementFn, comparator: this.comparator }); let index = 0; for (const current of this) { @@ -517,7 +506,7 @@ export class Heap extends IterableElementBase * @returns a new instance of the `Heap` class with the mapped elements. */ map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index f61c1c8..27db608 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -61,7 +61,7 @@ export class MaxHeap extends Heap { * @returns The `filter` method is returning a new `MaxHeap` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - override filter(callback: ElementCallback>, thisArg?: any): MaxHeap { + override filter(callback: ElementCallback, thisArg?: any): MaxHeap { const filteredList = new MaxHeap([], { toElementFn: this.toElementFn, comparator: this.comparator }); let index = 0; for (const current of this) { @@ -95,7 +95,7 @@ export class MaxHeap extends Heap { * @returns a new instance of the `MaxHeap` class with the mapped elements. */ override map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index 3a0af05..4370eac 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -49,7 +49,7 @@ export class MinHeap extends Heap { * @returns The `filter` method is returning a new `MinHeap` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - override filter(callback: ElementCallback>, thisArg?: any): MinHeap { + override filter(callback: ElementCallback, thisArg?: any): MinHeap { const filteredList = new MinHeap([], { toElementFn: this.toElementFn, comparator: this.comparator }); let index = 0; for (const current of this) { @@ -83,7 +83,7 @@ export class MinHeap extends Heap { * @returns a new instance of the `MinHeap` class with the mapped elements. */ override map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index c48a597..c76b003 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -6,7 +6,7 @@ * @license MIT License */ import type { DoublyLinkedListOptions, ElementCallback } from '../../types'; -import { IterableElementBase } from '../base'; +import { LinearLinkedBase } from '../base/linear-base'; export class DoublyLinkedListNode { /** @@ -22,60 +22,30 @@ export class DoublyLinkedListNode { protected _value: E; - /** - * The function returns the value of a protected variable. - * @returns The value of the variable `_value` is being returned. - */ get value(): E { return this._value; } - /** - * The above function sets the value of a variable. - * @param {E} value - The parameter "value" is of type E, which means it can be any type. - */ set value(value: E) { this._value = value; } protected _next: DoublyLinkedListNode | undefined; - /** - * The "next" function returns the next node in a doubly linked list. - * @returns The `next` property is being returned. It can be either a `DoublyLinkedListNode` - * object or `undefined`. - */ get next(): DoublyLinkedListNode | undefined { return this._next; } - /** - * The "next" property of a DoublyLinkedListNode is set to the provided value. - * @param {DoublyLinkedListNode | undefined} value - The `value` parameter is of type - * `DoublyLinkedListNode | undefined`. This means that it can accept either a - * `DoublyLinkedListNode` object or `undefined` as its value. - */ set next(value: DoublyLinkedListNode | undefined) { this._next = value; } protected _prev: DoublyLinkedListNode | undefined; - /** - * The `prev` function returns the previous node in a doubly linked list. - * @returns The `prev` property of the `DoublyLinkedListNode` class is being returned. It can either - * be a `DoublyLinkedListNode` object or `undefined`. - */ get prev(): DoublyLinkedListNode | undefined { return this._prev; } - /** - * The function sets the previous node of a doubly linked list node. - * @param {DoublyLinkedListNode | undefined} value - The `value` parameter is of type - * `DoublyLinkedListNode | undefined`. This means that it can accept either a - * `DoublyLinkedListNode` object or `undefined` as its value. - */ set prev(value: DoublyLinkedListNode | undefined) { this._prev = value; } @@ -513,7 +483,7 @@ export class DoublyLinkedListNode { * scheduler.clear(); * console.log(scheduler.listProcesses()); // [] */ -export class DoublyLinkedList extends IterableElementBase> { +export class DoublyLinkedList extends LinearLinkedBase> { /** * This TypeScript constructor initializes a DoublyLinkedList with optional elements and options. * @param {Iterable | Iterable} elements - The `elements` parameter in the constructor is an @@ -543,41 +513,22 @@ export class DoublyLinkedList extends IterableElementBase | undefined; - /** - * The `head` function returns the first node of a doubly linked list. - * @returns The method `getHead()` returns either a `DoublyLinkedListNode` object or `undefined`. - */ get head(): DoublyLinkedListNode | undefined { return this._head; } protected _tail: DoublyLinkedListNode | undefined; - /** - * The `tail` function returns the last node of a doubly linked list. - * @returns The `get tail()` method is returning either a `DoublyLinkedListNode` object or - * `undefined`. - */ get tail(): DoublyLinkedListNode | undefined { return this._tail; } protected _length: number; - /** - * The function returns the length of an object. - * @returns The length of the object, which is a number. - */ get length(): number { return this._length; } - protected _maxLen: number = -1; - - get maxLen() { - return this._maxLen; - } - /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -965,6 +916,28 @@ export class DoublyLinkedList extends IterableElementBase extends IterableElementBase | ((node: DoublyLinkedListNode) => boolean)} elementNodeOrPredicate - * elementNodeOrPredicate - The `indexOf` method takes in a parameter `elementNodeOrPredicate`, which - * can be one of the following: - * @returns The `indexOf` method returns the index of the element in the doubly linked list that - * matches the provided element, node, or predicate. If no match is found, it returns -1. - */ - indexOf(elementNodeOrPredicate: E | DoublyLinkedListNode | ((node: DoublyLinkedListNode) => boolean)): number { - const predicate = this._ensurePredicate(elementNodeOrPredicate); - let index = 0; - let current = this.head; - while (current) { - if (predicate(current)) { - return index; - } - index++; - current = current.next; - } - return -1; - } - /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -1142,40 +1090,6 @@ export class DoublyLinkedList extends IterableElementBase extends IterableElementBase { - return new DoublyLinkedList(this); + clone(): this { + return new DoublyLinkedList(this, { toElementFn: this._toElementFn, maxLen: this._maxLen }) as this; } /** @@ -1206,7 +1120,7 @@ export class DoublyLinkedList extends IterableElementBase>, thisArg?: any): DoublyLinkedList { + filter(callback: ElementCallback, thisArg?: any): DoublyLinkedList { const filteredList = new DoublyLinkedList([], { toElementFn: this.toElementFn }); let index = 0; for (const current of this) { @@ -1239,7 +1153,7 @@ export class DoublyLinkedList extends IterableElementBase( - callback: ElementCallback>, + callback: ElementCallback, toElementFn?: (rawElement: RM) => EM, thisArg?: any ): DoublyLinkedList { @@ -1339,4 +1253,30 @@ export class DoublyLinkedList extends IterableElementBase) => node.value === elementNodeOrPredicate; } + + /** + * The function `_createInstance` returns a new instance of `DoublyLinkedList` with the specified + * options. + * @param [options] - The `options` parameter in the `_createInstance` method is of type + * `DoublyLinkedListOptions`. It is an optional parameter that allows you to pass additional + * configuration options when creating a new instance of the `DoublyLinkedList` class. + * @returns An instance of the `DoublyLinkedList` class with an empty array and the provided options + * is being returned, cast as the current class type. + */ + protected override _createInstance(options?: DoublyLinkedListOptions): this { + return new DoublyLinkedList([], options) as this; + } + + /** + * The function returns an iterator that iterates over the elements of a data structure in reverse + * order. + */ + protected *_getReverseIterator(): IterableIterator { + let current = this.tail; + + while (current) { + yield current.value; + current = current.prev; + } + } } diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 77577e0..9c24c50 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -6,7 +6,7 @@ * @license MIT License */ import type { ElementCallback, SinglyLinkedListOptions } from '../../types'; -import { IterableElementBase } from '../base'; +import { LinearLinkedBase } from '../base/linear-base'; export class SinglyLinkedListNode { /** @@ -62,7 +62,7 @@ export class SinglyLinkedListNode { /** * */ -export class SinglyLinkedList extends IterableElementBase> { +export class SinglyLinkedList extends LinearLinkedBase> { constructor( elements: Iterable | Iterable | Iterable> = [], options?: SinglyLinkedListOptions @@ -70,8 +70,6 @@ export class SinglyLinkedList extends IterableElementBase 0 && maxLen % 1 === 0) this._maxLen = maxLen; } this.pushMany(elements); @@ -79,54 +77,26 @@ export class SinglyLinkedList extends IterableElementBase | undefined; - /** - * The `head` function returns the first node of a singly linked list. - * @returns The method is returning either a SinglyLinkedListNode object or undefined. - */ get head(): SinglyLinkedListNode | undefined { return this._head; } protected _tail: SinglyLinkedListNode | undefined; - /** - * The `tail` function returns the last node of a singly linked list. - * @returns The method is returning either a SinglyLinkedListNode object or undefined. - */ get tail(): SinglyLinkedListNode | undefined { return this._tail; } - /** - * The above function returns the value of the first element in a linked list, or undefined if the - * list is empty. - * @returns The value of the first node in the linked list, or undefined if the linked list is empty. - */ get first(): E | undefined { return this.head?.value; } - /** - * The function returns the value of the last element in a linked list, or undefined if the list is - * empty. - * @returns The value of the last node in the linked list, or undefined if the linked list is empty. - */ get last(): E | undefined { return this.tail?.value; } - protected _maxLen: number = -1; - - get maxLen() { - return this._maxLen; - } - protected _length: number = 0; - /** - * The function returns the length of an object. - * @returns The length of the object, which is a number. - */ get length(): number { return this._length; } @@ -475,6 +445,29 @@ export class SinglyLinkedList extends IterableElementBase extends IterableElementBase extends IterableElementBase | ((node: SinglyLinkedListNode) => boolean)} elementNodeOrPredicate - * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `indexOf` method can be one - * of the following types: - * @returns The `indexOf` method returns the index of the first occurrence of the element that - * matches the provided predicate in the singly linked list. If no matching element is found, it - * returns -1. - */ - indexOf(elementNodeOrPredicate: E | SinglyLinkedListNode | ((node: SinglyLinkedListNode) => boolean)): number { - const predicate = this._ensurePredicate(elementNodeOrPredicate); - let index = 0; - let current = this.head; - - while (current) { - if (predicate(current)) { - return index; - } - index++; - current = current.next; - } - - return -1; - } - /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -716,8 +663,8 @@ export class SinglyLinkedList extends IterableElementBase { - return new SinglyLinkedList(this, { toElementFn: this.toElementFn }); + clone(): this { + return new SinglyLinkedList(this, { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this; } /** @@ -737,7 +684,7 @@ export class SinglyLinkedList extends IterableElementBase>, thisArg?: any): SinglyLinkedList { + filter(callback: ElementCallback, thisArg?: any): SinglyLinkedList { const filteredList = new SinglyLinkedList([], { toElementFn: this.toElementFn }); let index = 0; for (const current of this) { @@ -770,7 +717,7 @@ export class SinglyLinkedList extends IterableElementBase( - callback: ElementCallback>, + callback: ElementCallback, toElementFn?: (rawElement: RM) => EM, thisArg?: any ): SinglyLinkedList { @@ -844,4 +791,29 @@ export class SinglyLinkedList extends IterableElementBase) => node.value === elementNodeOrPredicate; } + + /** + * The function `_createInstance` returns a new instance of `SinglyLinkedList` with the specified + * options. + * @param [options] - The `options` parameter in the `_createInstance` method is of type + * `SinglyLinkedListOptions`, which is used to configure the behavior of the `SinglyLinkedList` + * instance being created. It is an optional parameter, meaning it can be omitted when calling the + * method. + * @returns An instance of the `SinglyLinkedList` class with an empty array and the provided options + * is being returned. + */ + protected override _createInstance(options?: SinglyLinkedListOptions): this { + return new SinglyLinkedList([], options) as this; + } + + /** + * The function returns an iterator that iterates over the elements of a collection in reverse order. + */ + protected *_getReverseIterator(): IterableIterator { + const reversedArr = [...this].reverse(); + + for (const item of reversedArr) { + yield item; + } + } } diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 226a185..b042361 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -64,10 +64,7 @@ export class MaxPriorityQueue extends PriorityQueue { * @returns The `filter` method is returning a new `MaxPriorityQueue` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - override filter( - callback: ElementCallback>, - thisArg?: any - ): MaxPriorityQueue { + override filter(callback: ElementCallback, thisArg?: any): MaxPriorityQueue { const filteredPriorityQueue = new MaxPriorityQueue([], { toElementFn: this.toElementFn, comparator: this.comparator @@ -104,7 +101,7 @@ export class MaxPriorityQueue extends PriorityQueue { * @returns a new instance of the `MaxPriorityQueue` class with the mapped elements. */ override map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 7f2bbfe..5c7b9e3 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -53,10 +53,7 @@ export class MinPriorityQueue extends PriorityQueue { * @returns The `filter` method is returning a new `MinPriorityQueue` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - override filter( - callback: ElementCallback>, - thisArg?: any - ): MinPriorityQueue { + override filter(callback: ElementCallback, thisArg?: any): MinPriorityQueue { const filteredPriorityQueue = new MinPriorityQueue([], { toElementFn: this.toElementFn, comparator: this.comparator @@ -93,7 +90,7 @@ export class MinPriorityQueue extends PriorityQueue { * @returns a new instance of the `MinPriorityQueue` class with the mapped elements. */ override map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 0d48814..1d3d93a 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -55,7 +55,7 @@ export class PriorityQueue extends Heap { * @returns The `filter` method is returning a new `PriorityQueue` object that contains the elements that pass * the filter condition specified by the `callback` function. */ - override filter(callback: ElementCallback>, thisArg?: any): PriorityQueue { + override filter(callback: ElementCallback, thisArg?: any): PriorityQueue { const filteredPriorityQueue = new PriorityQueue([], { toElementFn: this.toElementFn, comparator: this.comparator @@ -92,7 +92,7 @@ export class PriorityQueue extends Heap { * @returns a new instance of the `PriorityQueue` class with the mapped elements. */ override map( - callback: ElementCallback>, + callback: ElementCallback, comparator: Comparator, toElementFn?: (rawElement: RM) => EM, thisArg?: any diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index b4ac0aa..215b6db 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -6,8 +6,8 @@ * @license MIT License */ import type { DequeOptions, ElementCallback, IterableWithSizeOrLength } from '../../types'; -import { IterableElementBase } from '../base'; import { calcMinUnitsRequired, rangeCheck } from '../../utils'; +import { LinearBase } from '../base/linear-base'; /** * 1. Operations at Both Ends: Supports adding and removing elements at both the front and back of the queue. This allows it to be used as a stack (last in, first out) and a queue (first in, first out). @@ -104,7 +104,7 @@ import { calcMinUnitsRequired, rangeCheck } from '../../utils'; * const k = 3; * console.log(maxSlidingWindow(nums, k)); // [3, 3, 5, 5, 6, 7] */ -export class Deque extends IterableElementBase> { +export class Deque extends LinearBase { /** * The constructor initializes a Deque object with optional iterable of elements and options. * @param elements - An iterable object (such as an array or a Set) that contains the initial @@ -120,9 +120,8 @@ export class Deque extends IterableElementBase 0 && maxLen % 1 === 0) this._maxLen = maxLen; } let _size: number; @@ -146,94 +145,48 @@ export class Deque extends IterableElementBase extends IterableElementBase> 1; } - /** - * The below function is a generator that yields elements from a collection one by one. - */ - *begin(): Generator { - let index = 0; - while (index < this._length) { - yield this.at(index); - index++; - } - } - - /** - * The function `reverseBegin()` is a generator that yields elements in reverse order starting from - * the last element. - */ - *reverseBegin(): Generator { - let index = this._length - 1; - while (index >= 0) { - yield this.at(index); - index--; - } - } - /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -658,6 +588,28 @@ export class Deque extends IterableElementBase= this._bucketSize) { + // bucketIndex++; + // indexInBucket = 0; + // } + // if (bucketIndex >= this._bucketCount) { + // bucketIndex = 0; + // } + // } + // return -1; + // } + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -704,28 +656,6 @@ export class Deque extends IterableElementBase - */ - sort(comparator?: (x: E, y: E) => number): this { - const arr: E[] = []; - for (let i = 0; i < this._length; ++i) { - arr.push(this.at(i)); - } - arr.sort(comparator); - for (let i = 0; i < this._length; ++i) { - this.setAt(i, arr[i]); - } - return this; - } - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -756,37 +686,6 @@ export class Deque extends IterableElementBase extends IterableElementBase { - return new Deque(this, { bucketSize: this.bucketSize, toElementFn: this.toElementFn }); + clone(): this { + return new Deque(this, { + bucketSize: this.bucketSize, + toElementFn: this.toElementFn, + maxLen: this._maxLen + }) as this; } /** @@ -816,7 +719,7 @@ export class Deque extends IterableElementBase>, thisArg?: any): Deque { + filter(predicate: ElementCallback, thisArg?: any): Deque { const newDeque = new Deque([], { bucketSize: this._bucketSize, toElementFn: this.toElementFn }); let index = 0; for (const el of this) { @@ -846,11 +749,7 @@ export class Deque extends IterableElementBase( - callback: ElementCallback>, - toElementFn?: (rawElement: RM) => EM, - thisArg?: any - ): Deque { + map(callback: ElementCallback, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Deque { const newDeque = new Deque([], { bucketSize: this._bucketSize, toElementFn }); let index = 0; for (const el of this) { @@ -931,4 +830,26 @@ export class Deque extends IterableElementBase`, which is an optional parameter that allows you to pass additional + * configuration options when creating a new instance of the `Deque` class. + * @returns An instance of the `Deque` class with an empty array and the provided options, casted as + * `this`. + */ + protected override _createInstance(options?: DequeOptions): this { + return new Deque([], options) as this; + } + + /** + * This function returns an iterator that iterates over elements in reverse order. + */ + protected *_getReverseIterator(): IterableIterator { + for (let i = this._length - 1; i > -1; i--) { + yield this.at(i); + } + } } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index a6cf6b5..0503789 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -4,8 +4,8 @@ * @class */ import type { ElementCallback, QueueOptions } from '../../types'; -import { IterableElementBase } from '../base'; import { SinglyLinkedList } from '../linked-list'; +import { LinearBase } from '../base/linear-base'; /** * 1. First In, First Out (FIFO): The core feature of a queue is its first in, first out nature. The element added to the queue first will be the one to be removed first. @@ -16,14 +16,13 @@ import { SinglyLinkedList } from '../linked-list'; * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited. * 7. Real-time Queuing: Like queuing systems in banks or supermarkets. */ -export class Queue extends IterableElementBase> { +export class Queue extends LinearBase { constructor(elements: Iterable | Iterable = [], options?: QueueOptions) { super(options); if (options) { - const { autoCompactRatio = 0.5, maxLen } = options; + const { autoCompactRatio = 0.5 } = options; this._autoCompactRatio = autoCompactRatio; - if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen; } this.pushMany(elements); @@ -35,30 +34,26 @@ export class Queue extends IterableElementBase extends IterableElementBase 0 ? this.elements[this.elements.length - 1] : undefined; } - protected _autoCompactRatio: number = 0.5; - - /** - * This function returns the value of the autoCompactRatio property. - * @returns The `autoCompactRatio` property of the object, which is a number. - */ - get autoCompactRatio(): number { - return this._autoCompactRatio; - } - - /** - * The above function sets the autoCompactRatio property to a specified number in TypeScript. - * @param {number} v - The parameter `v` represents the value that will be assigned to the - * `_autoCompactRatio` property. - */ - set autoCompactRatio(v: number) { - this._autoCompactRatio = v; - } - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -209,6 +185,60 @@ export class Queue extends IterableElementBase this.length) return false; + this._elements.splice(this.offset + index, 0, newElement); + return true; + } + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function `setAt` updates an element at a specified index in an array-like data structure. + * @param {number} index - The `index` parameter is a number that represents the position in the + * array where the new element will be set. + * @param {E} newElement - The `newElement` parameter represents the new value that you want to set + * at the specified index in the array. + * @returns The `setAt` method returns a boolean value - `true` if the element was successfully set + * at the specified index, and `false` if the index is out of bounds (less than 0 or greater than the + * length of the array). + */ + setAt(index: number, newElement: E): boolean { + if (index < 0 || index > this.length) return false; + this._elements[this.offset + index] = newElement; + return true; + } + /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -220,17 +250,6 @@ export class Queue extends IterableElementBase extends IterableElementBase { - return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn }); + clone(): this { + return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this; } /** @@ -283,7 +302,7 @@ export class Queue extends IterableElementBase>, thisArg?: any): Queue { + filter(predicate: ElementCallback, thisArg?: any): Queue { const newDeque = new Queue([], { toElementFn: this.toElementFn }); let index = 0; for (const el of this) { @@ -313,11 +332,7 @@ export class Queue extends IterableElementBase( - callback: ElementCallback>, - toElementFn?: (rawElement: RM) => EM, - thisArg?: any - ): Queue { + map(callback: ElementCallback, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Queue { const newDeque = new Queue([], { toElementFn }); let index = 0; for (const el of this) { @@ -338,6 +353,30 @@ export class Queue extends IterableElementBase`, which is used to configure the behavior of the queue being created. It + * allows you to specify settings or properties that can influence how the queue operates. + * @returns An instance of the `Queue` class with an empty array and the provided options is being + * returned. + */ + protected override _createInstance(options?: QueueOptions): this { + return new Queue([], options) as this; + } + + /** + * The function `_getReverseIterator` returns an iterator that iterates over elements in reverse + * order. + */ + protected *_getReverseIterator(): IterableIterator { + for (let i = this.length - 1; i >= 0; i--) { + const cur = this.at(i); // `at()` handles the offset. + if (cur !== undefined) yield cur; + } + } } /** @@ -355,7 +394,7 @@ export class LinkedListQueue extends SinglyLinkedList { * @returns The `clone()` method is returning a new instance of `LinkedListQueue` with the same * values as the original `LinkedListQueue`. */ - override clone(): LinkedListQueue { - return new LinkedListQueue(this, { toElementFn: this.toElementFn }); + override clone(): this { + return new LinkedListQueue(this, { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this; } } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 59ede59..f0c090c 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -16,7 +16,7 @@ import { IterableElementBase } from '../base'; * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence. * 6. Backtracking Algorithms: In problems where multiple branches need to be explored but only one branch can be explored at a time, stacks can be used to save the state at each branching point. */ -export class Stack extends IterableElementBase> { +export class Stack extends IterableElementBase { constructor(elements: Iterable | Iterable = [], options?: StackOptions) { super(options); this.pushMany(elements); @@ -153,17 +153,6 @@ export class Stack extends IterableElementBase extends IterableElementBase>, thisArg?: any): Stack { + filter(predicate: ElementCallback, thisArg?: any): Stack { const newStack = new Stack([], { toElementFn: this.toElementFn }); let index = 0; for (const el of this) { @@ -230,11 +219,7 @@ export class Stack extends IterableElementBase( - callback: ElementCallback>, - toElementFn?: (rawElement: RM) => EM, - thisArg?: any - ): Stack { + map(callback: ElementCallback, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Stack { const newStack = new Stack([], { toElementFn }); let index = 0; for (const el of this) { diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 73517b9..1f5ad4e 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -170,7 +170,7 @@ export class TrieNode { * const subnet = ip.split('.').slice(0, 3).join('.'); * console.log(ipRoutingTable.hasPrefix(subnet)); // true */ -export class Trie extends IterableElementBase> { +export class Trie extends IterableElementBase { /** * The constructor initializes a Trie data structure with optional options and words provided as * input. @@ -545,7 +545,7 @@ export class Trie extends IterableElementBase> { * specific object as the context for the `predicate` function. If `thisArg` is provided, it will be * @returns The `filter` method is returning an array of strings (`string[]`). */ - filter(predicate: ElementCallback>, thisArg?: any): Trie { + filter(predicate: ElementCallback, thisArg?: any): Trie { const results = new Trie([], { toElementFn: this.toElementFn, caseSensitive: this.caseSensitive }); let index = 0; for (const word of this) { @@ -576,7 +576,7 @@ export class Trie extends IterableElementBase> { * @returns a new Trie object. */ map( - callback: ElementCallback>, + callback: ElementCallback, toElementFn?: (rawElement: RM) => string, thisArg?: any ): Trie { @@ -609,6 +609,10 @@ export class Trie extends IterableElementBase> { yield* _dfs(this.root, ''); } + protected get _total() { + return this._size; + } + /** * Time Complexity: O(l), where l is the length of the input string. * Space Complexity: O(1) - Constant space. diff --git a/src/types/data-structures/base/base.ts b/src/types/data-structures/base/base.ts index b816749..36c3c0b 100644 --- a/src/types/data-structures/base/base.ts +++ b/src/types/data-structures/base/base.ts @@ -1,25 +1,34 @@ import { IterableElementBase, IterableEntryBase } from '../../../data-structures'; +import { LinearBase } from '../../../data-structures/base/linear-base'; -export type EntryCallback = (key: K, value: V, index: number, container: IterableEntryBase) => R; -export type ElementCallback = (element: E, index: number, container: IterableElementBase) => RT; +export type EntryCallback = (key: K, value: V, index: number, original: IterableEntryBase) => R; +export type ElementCallback = (element: E, index: number, original: IterableElementBase) => RT; export type ReduceEntryCallback = ( accumulator: R, value: V, key: K, index: number, - container: IterableEntryBase + original: IterableEntryBase ) => R; -export type ReduceElementCallback = ( + +export type ReduceElementCallback = ( accumulator: RT, element: E, index: number, - container: IterableElementBase + original: IterableElementBase ) => RT; -// export type IterableEntryBaseOptions = { -// toEntryFn?: (rawElement: R) => BTNEntry; -// }; +export type ReduceLinearCallback = ( + accumulator: RT, + element: E, + index: number, + original: LinearBase +) => RT; export type IterableElementBaseOptions = { toElementFn?: (rawElement: R) => E; }; + +export type LinearBaseOptions = IterableElementBaseOptions & { + maxLen?: number; +}; diff --git a/src/types/data-structures/linked-list/doubly-linked-list.ts b/src/types/data-structures/linked-list/doubly-linked-list.ts index 5883a71..dea5747 100644 --- a/src/types/data-structures/linked-list/doubly-linked-list.ts +++ b/src/types/data-structures/linked-list/doubly-linked-list.ts @@ -1,5 +1,3 @@ -import { IterableElementBaseOptions } from '../base'; +import { LinearBaseOptions } from '../base'; -export type DoublyLinkedListOptions = IterableElementBaseOptions & { - maxLen?: number; -}; +export type DoublyLinkedListOptions = LinearBaseOptions & {}; diff --git a/src/types/data-structures/linked-list/singly-linked-list.ts b/src/types/data-structures/linked-list/singly-linked-list.ts index 200f84c..a6a7c39 100644 --- a/src/types/data-structures/linked-list/singly-linked-list.ts +++ b/src/types/data-structures/linked-list/singly-linked-list.ts @@ -1,5 +1,3 @@ -import { IterableElementBaseOptions } from '../base'; +import { LinearBaseOptions } from '../base'; -export type SinglyLinkedListOptions = IterableElementBaseOptions & { - maxLen?: number; -}; +export type SinglyLinkedListOptions = LinearBaseOptions & {}; diff --git a/src/types/data-structures/queue/deque.ts b/src/types/data-structures/queue/deque.ts index 05438ac..e079b1a 100644 --- a/src/types/data-structures/queue/deque.ts +++ b/src/types/data-structures/queue/deque.ts @@ -1,6 +1,5 @@ -import { IterableElementBaseOptions } from '../base'; +import { LinearBaseOptions } from '../base'; export type DequeOptions = { bucketSize?: number; - maxLen?: number; -} & IterableElementBaseOptions; +} & LinearBaseOptions; diff --git a/src/types/data-structures/queue/queue.ts b/src/types/data-structures/queue/queue.ts index 75185f5..8212c66 100644 --- a/src/types/data-structures/queue/queue.ts +++ b/src/types/data-structures/queue/queue.ts @@ -1,6 +1,5 @@ -import { IterableElementBaseOptions } from '../base'; +import { LinearBaseOptions } from '../base'; -export type QueueOptions = IterableElementBaseOptions & { +export type QueueOptions = LinearBaseOptions & { autoCompactRatio?: number; - maxLen?: number; }; 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 bd47dd7..aa2f03b 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 @@ -1,4 +1,4 @@ -import { DoublyLinkedList, DoublyLinkedListNode, SinglyLinkedList } from '../../../../src'; +import { DoublyLinkedList, DoublyLinkedListNode } from '../../../../src'; describe('DoublyLinkedListNode', () => { it('should DoublyLinkedListNode', () => { @@ -466,6 +466,95 @@ describe('DoublyLinkedList Operation Test', () => { }); }); +describe('DoublyLinkedList Additional Methods', () => { + // Slice method implementation and test + test('slice should return a new list with specified range', () => { + const list = new DoublyLinkedList([1, 2, 3, 4, 5]); + const slicedList = list.slice(1, 4); + + expect(slicedList.toArray()).toEqual([2, 3, 4]); + expect(list.length).toBe(5); // Original list unchanged + }); + + // Splice method implementation + test('splice should modify list and return removed elements', () => { + const list = new DoublyLinkedList([1, 2, 3, 4, 5]); + const removedList = list.splice(2, 2, 6, 7); + + expect(list.toArray()).toEqual([1, 2, 6, 7, 5]); + expect(removedList.toArray()).toEqual([3, 4]); + }); + + // Concat method test + test('concat should combine multiple lists', () => { + const list1 = new DoublyLinkedList([1, 2]); + const list2 = new DoublyLinkedList([3, 4]); + const list3 = new DoublyLinkedList([5, 6]); + + const concatenatedList = list1.concat(list2, list3); + expect(concatenatedList.toArray()).toEqual([1, 2, 3, 4, 5, 6]); + }); + + // Sort method test + test('sort should order elements in ascending order', () => { + const list = new DoublyLinkedList([5, 2, 8, 1, 9]); + list.sort((a, b) => a - b); + + expect(list.toArray()).toEqual([1, 2, 5, 8, 9]); + }); + + // Reverse method test + test('reverse should invert the list order', () => { + const list = new DoublyLinkedList([1, 2, 3, 4, 5]); + list.reverse(); + + expect(list.toArray()).toEqual([5, 4, 3, 2, 1]); + }); + + // Join method test + test('join should convert list to string with separator', () => { + const list = new DoublyLinkedList(['a', 'b', 'c']); + + expect(list.join('-')).toBe('a-b-c'); + expect(list.join()).toBe('a,b,c'); + }); + + // IndexOf method test + test('indexOf should return first occurrence index', () => { + const list = new DoublyLinkedList([1, 2, 3, 2, 1]); + + expect(list.indexOf(2)).toBe(1); + expect(list.indexOf(4)).toBe(-1); + }); + + // LastIndexOf method test + test('lastIndexOf should return last occurrence index', () => { + const list = new DoublyLinkedList([1, 2, 3, 2, 1]); + + expect(list.lastIndexOf(2)).toBe(3); + expect(list.lastIndexOf(4)).toBe(-1); + }); + + // findIndex method test + test('findIndex should return first occurrence index', () => { + const list = new DoublyLinkedList([1, 2, 3, 2, 1]); + expect(list.findIndex(item => item === 2)).toBe(1); + expect(list.findIndex(item => item === 4)).toBe(-1); + }); + + // fill method test + test('fill should return fill all the list', () => { + let list = new DoublyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9)]).toEqual([9, 9, 9, 9, 9]); + list = new DoublyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, 2, 3)]).toEqual([1, 2, 9, 2, 1]); + list = new DoublyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, -3, -2)]).toEqual([1, 2, 9, 2, 1]); + list = new DoublyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, -2, -3)]).toEqual([1, 2, 3, 2, 1]); + }); +}); + describe('iterable methods', () => { it('should forEach, some, every, filter, map, reduce of the deque', () => { const dl = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index e1a432b..041650e 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -458,6 +458,95 @@ describe('SinglyLinkedList Operation Test', () => { }); }); +describe('SinglyLinkedList Additional Methods', () => { + // Slice method implementation and test + test('slice should return a new list with specified range', () => { + const list = new SinglyLinkedList([1, 2, 3, 4, 5]); + const slicedList = list.slice(1, 4); + + expect(slicedList.toArray()).toEqual([2, 3, 4]); + expect(list.length).toBe(5); // Original list unchanged + }); + + // Splice method implementation + test('splice should modify list and return removed elements', () => { + const list = new SinglyLinkedList([1, 2, 3, 4, 5]); + const removedList = list.splice(2, 2, 6, 7); + + expect(list.toArray()).toEqual([1, 2, 6, 7, 5]); + expect(removedList.toArray()).toEqual([3, 4]); + }); + + // Concat method test + test('concat should combine multiple lists', () => { + const list1 = new SinglyLinkedList([1, 2]); + const list2 = new SinglyLinkedList([3, 4]); + const list3 = new SinglyLinkedList([5, 6]); + + const concatenatedList = list1.concat(list2, list3); + expect(concatenatedList.toArray()).toEqual([1, 2, 3, 4, 5, 6]); + }); + + // Sort method test + test('sort should order elements in ascending order', () => { + const list = new SinglyLinkedList([5, 2, 8, 1, 9]); + list.sort((a, b) => a - b); + + expect(list.toArray()).toEqual([1, 2, 5, 8, 9]); + }); + + // Reverse method test + test('reverse should invert the list order', () => { + const list = new SinglyLinkedList([1, 2, 3, 4, 5]); + list.reverse(); + + expect(list.toArray()).toEqual([5, 4, 3, 2, 1]); + }); + + // Join method test + test('join should convert list to string with separator', () => { + const list = new SinglyLinkedList(['a', 'b', 'c']); + + expect(list.join('-')).toBe('a-b-c'); + expect(list.join()).toBe('a,b,c'); + }); + + // IndexOf method test + test('indexOf should return first occurrence index', () => { + const list = new SinglyLinkedList([1, 2, 3, 2, 1]); + + expect(list.indexOf(2)).toBe(1); + expect(list.indexOf(4)).toBe(-1); + }); + + // LastIndexOf method test + test('lastIndexOf should return last occurrence index', () => { + const list = new SinglyLinkedList([1, 2, 3, 2, 1]); + + expect(list.lastIndexOf(2)).toBe(3); + expect(list.lastIndexOf(4)).toBe(-1); + }); + + // findIndex method test + test('findIndex should return first occurrence index', () => { + const list = new SinglyLinkedList([1, 2, 3, 2, 1]); + expect(list.findIndex(item => item === 2)).toBe(1); + expect(list.findIndex(item => item === 4)).toBe(-1); + }); + + // fill method test + test('fill should return fill all the list', () => { + let list = new SinglyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9)]).toEqual([9, 9, 9, 9, 9]); + list = new SinglyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, 2, 3)]).toEqual([1, 2, 9, 2, 1]); + list = new SinglyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, -3, -2)]).toEqual([1, 2, 9, 2, 1]); + list = new SinglyLinkedList([1, 2, 3, 2, 1]); + expect([...list.fill(9, -2, -3)]).toEqual([1, 2, 3, 2, 1]); + }); +}); + describe('SinglyLinkedList', () => { let list: SinglyLinkedList; @@ -555,7 +644,8 @@ describe('iterable methods', () => { expect(sl.some(element => element > 2)).toBe(true); expect([...sl.filter(element => element > 2)]).toEqual([3]); - expect([...sl.map(element => element * 2)]).toEqual([2, 4, 6]); + const mappedSl = sl.map(element => element * 2); + expect([...mappedSl]).toEqual([2, 4, 6]); expect(sl.reduce((accumulator, element) => accumulator + element, 0)).toEqual(6); }); }); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 44ec317..2dfe957 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -382,21 +382,21 @@ describe('Deque - Additional Operations', () => { expect(deque.isEmpty()).toBeTruthy(); }); - it('begin should yield elements from the beginning', () => { - deque.push(1); - deque.push(2); - const iterator = deque.begin(); - expect(iterator.next().value).toBe(1); - expect(iterator.next().value).toBe(2); - }); + // it('begin should yield elements from the beginning', () => { + // deque.push(1); + // deque.push(2); + // const iterator = deque.begin(); + // expect(iterator.next().value).toBe(1); + // expect(iterator.next().value).toBe(2); + // }); - it('reverseBegin should yield elements in reverse order', () => { - deque.push(1); - deque.push(2); - const iterator = deque.reverseBegin(); - expect(iterator.next().value).toBe(2); - expect(iterator.next().value).toBe(1); - }); + // it('reverseBegin should yield elements in reverse order', () => { + // deque.push(1); + // deque.push(2); + // const iterator = deque.reverseBegin(); + // expect(iterator.next().value).toBe(2); + // expect(iterator.next().value).toBe(1); + // }); }); describe('Deque - push Method', () => { let deque: Deque; @@ -543,6 +543,95 @@ describe('Deque - shift Method', () => { }); }); +describe('Deque Additional Methods', () => { + // Slice method implementation and test + test('slice should return a new list with specified range', () => { + const list = new Deque([1, 2, 3, 4, 5]); + const slicedList = list.slice(1, 4); + + expect(slicedList.toArray()).toEqual([2, 3, 4]); + expect(list.length).toBe(5); // Original list unchanged + }); + + // Splice method implementation + test('splice should modify list and return removed elements', () => { + const list = new Deque([1, 2, 3, 4, 5]); + const removedList = list.splice(2, 2, 6, 7); + + expect(list.toArray()).toEqual([1, 2, 6, 7, 5]); + expect(removedList.toArray()).toEqual([3, 4]); + }); + + // Concat method test + test('concat should combine multiple lists', () => { + const list1 = new Deque([1, 2]); + const list2 = new Deque([3, 4]); + const list3 = new Deque([5, 6]); + + const concatenatedList = list1.concat(list2, list3); + expect(concatenatedList.toArray()).toEqual([1, 2, 3, 4, 5, 6]); + }); + + // Sort method test + test('sort should order elements in ascending order', () => { + const list = new Deque([5, 2, 8, 1, 9]); + list.sort((a, b) => a - b); + + expect(list.toArray()).toEqual([1, 2, 5, 8, 9]); + }); + + // Reverse method test + test('reverse should invert the list order', () => { + const list = new Deque([1, 2, 3, 4, 5]); + list.reverse(); + + expect(list.toArray()).toEqual([5, 4, 3, 2, 1]); + }); + + // Join method test + test('join should convert list to string with separator', () => { + const list = new Deque(['a', 'b', 'c']); + + expect(list.join('-')).toBe('a-b-c'); + expect(list.join()).toBe('a,b,c'); + }); + + // IndexOf method test + test('indexOf should return first occurrence index', () => { + const list = new Deque([1, 2, 3, 2, 1]); + + expect(list.indexOf(2)).toBe(1); + expect(list.indexOf(4)).toBe(-1); + }); + + // LastIndexOf method test + test('lastIndexOf should return last occurrence index', () => { + const list = new Deque([1, 2, 3, 2, 1]); + + expect(list.lastIndexOf(2)).toBe(3); + expect(list.lastIndexOf(4)).toBe(-1); + }); + + // findIndex method test + test('findIndex should return first occurrence index', () => { + const list = new Deque([1, 2, 3, 2, 1]); + expect(list.findIndex(item => item === 2)).toBe(1); + expect(list.findIndex(item => item === 4)).toBe(-1); + }); + + // fill method test + test('fill should return fill all the list', () => { + let list = new Deque([1, 2, 3, 2, 1]); + expect([...list.fill(9)]).toEqual([9, 9, 9, 9, 9]); + list = new Deque([1, 2, 3, 2, 1]); + expect([...list.fill(9, 2, 3)]).toEqual([1, 2, 9, 2, 1]); + list = new Deque([1, 2, 3, 2, 1]); + expect([...list.fill(9, -3, -2)]).toEqual([1, 2, 9, 2, 1]); + list = new Deque([1, 2, 3, 2, 1]); + expect([...list.fill(9, -2, -3)]).toEqual([1, 2, 3, 2, 1]); + }); +}); + describe('Deque', () => { it('should initialize with default iterable with length function', () => { class IterableNumbers { diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index e6d334f..c02e687 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -298,6 +298,95 @@ describe('Queue - Additional Methods', () => { }); }); +describe('Queue Additional Methods', () => { + // Slice method implementation and test + test('slice should return a new list with specified range', () => { + const list = new Queue([1, 2, 3, 4, 5]); + const slicedList = list.slice(1, 4); + + expect(slicedList.toArray()).toEqual([2, 3, 4]); + expect(list.length).toBe(5); // Original list unchanged + }); + + // Splice method implementation + test('splice should modify list and return removed elements', () => { + const list = new Queue([1, 2, 3, 4, 5]); + const removedList = list.splice(2, 2, 6, 7); + + expect(list.toArray()).toEqual([1, 2, 6, 7, 5]); + expect(removedList.toArray()).toEqual([3, 4]); + }); + + // Concat method test + test('concat should combine multiple lists', () => { + const list1 = new Queue([1, 2]); + const list2 = new Queue([3, 4]); + const list3 = new Queue([5, 6]); + + const concatenatedList = list1.concat(list2, list3); + expect(concatenatedList.toArray()).toEqual([1, 2, 3, 4, 5, 6]); + }); + + // Sort method test + test('sort should order elements in ascending order', () => { + const list = new Queue([5, 2, 8, 1, 9]); + list.sort((a, b) => a - b); + + expect(list.toArray()).toEqual([1, 2, 5, 8, 9]); + }); + + // Reverse method test + test('reverse should invert the list order', () => { + const list = new Queue([1, 2, 3, 4, 5]); + list.reverse(); + + expect(list.toArray()).toEqual([5, 4, 3, 2, 1]); + }); + + // Join method test + test('join should convert list to string with separator', () => { + const list = new Queue(['a', 'b', 'c']); + + expect(list.join('-')).toBe('a-b-c'); + expect(list.join()).toBe('a,b,c'); + }); + + // IndexOf method test + test('indexOf should return first occurrence index', () => { + const list = new Queue([1, 2, 3, 2, 1]); + + expect(list.indexOf(2)).toBe(1); + expect(list.indexOf(4)).toBe(-1); + }); + + // LastIndexOf method test + test('lastIndexOf should return last occurrence index', () => { + const list = new Queue([1, 2, 3, 2, 1]); + + expect(list.lastIndexOf(2)).toBe(3); + expect(list.lastIndexOf(4)).toBe(-1); + }); + + // findIndex method test + test('findIndex should return first occurrence index', () => { + const list = new Queue([1, 2, 3, 2, 1]); + expect(list.findIndex(item => item === 2)).toBe(1); + expect(list.findIndex(item => item === 4)).toBe(-1); + }); + + // fill method test + test('fill should return fill all the list', () => { + let list = new Queue([1, 2, 3, 2, 1]); + expect([...list.fill(9)]).toEqual([9, 9, 9, 9, 9]); + list = new Queue([1, 2, 3, 2, 1]); + expect([...list.fill(9, 2, 3)]).toEqual([1, 2, 9, 2, 1]); + list = new Queue([1, 2, 3, 2, 1]); + expect([...list.fill(9, -3, -2)]).toEqual([1, 2, 9, 2, 1]); + list = new Queue([1, 2, 3, 2, 1]); + expect([...list.fill(9, -2, -3)]).toEqual([1, 2, 3, 2, 1]); + }); +}); + describe('Queue - Static and Clone Methods', () => { it('fromArray should create a new queue from an array', () => { const array = [1, 2, 3];