diff --git a/README.md b/README.md index c6aeb2b..8a892d0 100644 --- a/README.md +++ b/README.md @@ -736,43 +736,43 @@ Version 11.7.9 [//]: # (No deletion!!! Start of Replace Section)
heap
-
test nametime taken (ms)executions per secsample deviation
100,000 add6.38156.712.05e-4
100,000 add & poll31.5331.718.78e-4
+
test nametime taken (ms)executions per secsample deviation
100,000 add6.43155.581.69e-4
100,000 add & poll34.9528.617.35e-4
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add58.6817.049.39e-4
100,000 add randomly75.4913.250.00
100,000 get90.4811.050.00
100,000 iterator29.7133.660.01
100,000 add & delete orderly122.028.200.00
100,000 add & delete randomly214.394.660.02
+
test nametime taken (ms)executions per secsample deviation
100,000 add78.9012.670.00
100,000 add randomly82.7412.090.00
100,000 get111.798.950.00
100,000 iterator26.6237.560.01
100,000 add & delete orderly152.366.560.00
100,000 add & delete randomly230.544.340.00
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push42.6723.440.01
100,000 push & shift4.92203.057.10e-4
Native JS Array 100,000 push & shift2380.400.420.24
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push42.9223.300.01
100,000 push & shift4.90203.915.57e-4
Native JS Array 100,000 push & shift2372.320.420.25
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push24.9740.040.00
1,000,000 push & pop30.7532.520.00
1,000,000 push & shift30.6032.670.00
100,000 push & shift3.22310.212.47e-4
Native JS Array 100,000 push & shift2153.500.460.13
100,000 unshift & shift2.89345.712.85e-4
Native JS Array 100,000 unshift & shift4177.840.240.28
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push24.6140.640.00
1,000,000 push & pop31.0932.170.00
1,000,000 push & shift30.7932.480.00
100,000 push & shift3.35298.196.23e-4
Native JS Array 100,000 push & shift2214.500.450.36
100,000 unshift & shift2.90344.252.69e-4
Native JS Array 100,000 unshift & shift4256.150.230.15
hash-map
-
test nametime taken (ms)executions per secsample deviation
1,000,000 set116.958.550.03
Native JS Map 1,000,000 set206.874.830.01
Native JS Set 1,000,000 add167.655.960.01
1,000,000 set & get122.708.150.03
Native JS Map 1,000,000 set & get263.263.800.01
Native JS Set 1,000,000 add & has167.725.960.01
1,000,000 ObjKey set & get320.173.120.03
Native JS Map 1,000,000 ObjKey set & get292.053.420.02
Native JS Set 1,000,000 ObjKey add & has267.273.740.02
+
test nametime taken (ms)executions per secsample deviation
1,000,000 set116.378.590.02
Native JS Map 1,000,000 set210.434.750.02
Native JS Set 1,000,000 add181.965.500.02
1,000,000 set & get121.638.220.02
Native JS Map 1,000,000 set & get269.233.710.01
Native JS Set 1,000,000 add & has185.335.400.03
1,000,000 ObjKey set & get325.113.080.03
Native JS Map 1,000,000 ObjKey set & get308.213.240.03
Native JS Set 1,000,000 ObjKey add & has270.593.700.03
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push43.9322.765.85e-4
100,000 getWords83.4211.990.00
+
test nametime taken (ms)executions per secsample deviation
100,000 push46.9421.300.00
100,000 getWords105.459.480.01
avl-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add232.604.300.00
100,000 add randomly306.923.260.00
100,000 get113.288.830.00
100,000 iterator33.2030.120.01
100,000 add & delete orderly399.102.510.00
100,000 add & delete randomly551.571.810.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add274.903.640.01
100,000 add randomly398.942.510.02
100,000 get141.337.080.01
100,000 iterator32.2531.010.00
100,000 add & delete orderly446.472.240.00
100,000 add & delete randomly625.711.600.03
binary-tree-overall
-
test nametime taken (ms)executions per secsample deviation
10,000 RBTree add randomly6.24160.311.80e-4
10,000 RBTree get randomly7.93126.098.91e-5
10,000 RBTree add & delete randomly17.0558.651.66e-4
10,000 AVLTree add randomly21.9045.662.09e-4
10,000 AVLTree get randomly8.68115.150.00
10,000 AVLTree add & delete randomly41.6624.006.11e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 RBTree add randomly6.69149.441.04e-4
10,000 RBTree get randomly9.22108.471.36e-4
10,000 RBTree add & delete randomly18.5953.790.00
10,000 AVLTree add randomly24.7340.432.93e-4
10,000 AVLTree get randomly9.77102.319.04e-5
10,000 AVLTree add & delete randomly46.1821.657.76e-4
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109614.917.24e-6
1,000 addEdge6.68149.815.43e-4
1,000 getVertex0.052.18e+43.02e-7
1,000 getEdge21.4646.600.00
tarjan204.994.880.03
topologicalSort166.176.020.00
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109860.118.96e-7
1,000 addEdge6.23160.444.50e-4
1,000 getVertex0.052.09e+41.05e-5
1,000 getEdge25.1839.720.01
tarjan205.334.870.01
topologicalSort186.145.370.02
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push217.484.600.04
1,000,000 unshift221.644.510.02
1,000,000 unshift & shift175.585.700.03
1,000,000 addBefore311.893.210.04
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push228.044.390.03
1,000,000 unshift235.674.240.07
1,000,000 unshift & shift198.315.040.02
1,000,000 addBefore314.033.180.05
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift211.024.740.04
10,000 push & pop216.294.620.01
10,000 addBefore248.754.020.01
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift236.114.240.05
10,000 push & pop220.244.540.01
10,000 addBefore246.874.050.00
priority-queue
-
test nametime taken (ms)executions per secsample deviation
100,000 add27.5336.320.00
100,000 add & poll76.9513.000.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add27.3436.579.52e-4
100,000 add & poll77.8512.850.01
stack
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push39.3925.390.01
1,000,000 push & pop47.7220.960.01
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push38.5025.970.00
1,000,000 push & pop46.8221.360.00
[//]: # (No deletion!!! End of Replace Section) diff --git a/src/data-structures/base/index.ts b/src/data-structures/base/index.ts index 91ebe1f..16e46bf 100644 --- a/src/data-structures/base/index.ts +++ b/src/data-structures/base/index.ts @@ -1 +1,2 @@ -export * from './iterable-base'; +export * from './iterable-entry-base'; +export * from './iterable-element-base'; diff --git a/src/data-structures/base/iterable-element-base.ts b/src/data-structures/base/iterable-element-base.ts new file mode 100644 index 0000000..35d6c8b --- /dev/null +++ b/src/data-structures/base/iterable-element-base.ts @@ -0,0 +1,250 @@ +import { ElementCallback, IterableElementBaseOptions, ReduceElementCallback } from '../../types'; + +export abstract class IterableElementBase { + /** + * The protected constructor initializes the options for the IterableElementBase class, including the + * toElementFn function. + * @param [options] - An optional object that contains the following properties: + */ + protected constructor(options?: IterableElementBaseOptions) { + if (options) { + const { toElementFn } = options; + if (typeof toElementFn === 'function') this._toElementFn = toElementFn; + else if (toElementFn) throw new TypeError('toElementFn must be a function type'); + } + } + + 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; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function is an implementation of the Symbol.iterator method that returns an IterableIterator. + * @param {any[]} args - The `args` parameter in the code snippet represents a rest parameter. It + * allows the function to accept any number of arguments as an array. In this case, the `args` + * parameter is used to pass any number of arguments to the `_getIterator` method. + */ + * [Symbol.iterator](...args: any[]): IterableIterator { + yield* this._getIterator(...args); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The function returns an iterator that yields all the values in the object. + */ + * values(): IterableIterator { + for (const item of this) { + yield item; + } + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `every` function checks if every element in the array satisfies a given predicate. + * @param predicate - The `predicate` parameter is a callback function that takes three arguments: + * the current element being processed, its index, and the array it belongs to. It should return a + * boolean value indicating whether the element satisfies a certain condition or not. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `predicate` function. If `thisArg` is + * @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 { + let index = 0; + for (const item of this) { + if (!predicate.call(thisArg, item, index++, this)) { + return false; + } + } + return true; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The "some" function checks if at least one element in a collection satisfies a given predicate. + * @param predicate - The `predicate` parameter is a callback function that takes three arguments: + * `value`, `index`, and `array`. It should return a boolean value indicating whether the current + * element satisfies the condition. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided, + * it will be passed as the `this` value to the `predicate` function. If `thisArg + * @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 { + let index = 0; + for (const item of this) { + if (predicate.call(thisArg, item, index++, this)) { + return true; + } + } + return false; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `forEach` function iterates over each element in an array-like object and calls a callback + * function for each element. + * @param callbackfn - The callbackfn 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 that forEach was called upon. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * 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 { + let index = 0; + for (const item of this) { + callbackfn.call(thisArg, item, index++, this); + } + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * 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 + * 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. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * 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 + * @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 { + let index = 0; + for (const item of this) { + if (callbackfn.call(thisArg, item, index++, this)) return item; + } + + return; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function checks if a given element exists in a collection. + * @param {E} element - The parameter "element" is of type E, which means it can be any type. It + * represents the element that we want to check for existence in the collection. + * @returns a boolean value. It returns true if the element is found in the collection, and false + * otherwise. + */ + has(element: E): boolean { + for (const ele of this) { + if (ele === element) return true; + } + return false; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `reduce` function iterates over the elements of an array-like object and applies a callback + * function to reduce them into a single value. + * @param callbackfn - The callbackfn parameter is a function that will be called for each element in + * the array. It takes four arguments: + * @param {U} initialValue - The initialValue parameter is the initial value of the accumulator. It + * is the value that the accumulator starts with before the reduction operation begins. + * @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; + let index = 0; + for (const item of this) { + accumulator = callbackfn(accumulator, item as E, index++, this); + } + return accumulator; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The print function logs the elements of an array to the console. + */ + print(): void { + console.log([...this]); + } + + abstract isEmpty(): boolean; + + abstract clear(): void; + + abstract clone(): C; + + abstract map(...args: any[]): any; + + abstract filter(...args: any[]): any; + + protected abstract _getIterator(...args: any[]): IterableIterator; +} diff --git a/src/data-structures/base/iterable-base.ts b/src/data-structures/base/iterable-entry-base.ts similarity index 56% rename from src/data-structures/base/iterable-base.ts rename to src/data-structures/base/iterable-entry-base.ts index bda732f..405c4f8 100644 --- a/src/data-structures/base/iterable-base.ts +++ b/src/data-structures/base/iterable-entry-base.ts @@ -1,6 +1,14 @@ -import { ElementCallback, EntryCallback, ReduceElementCallback, ReduceEntryCallback } from '../../types'; +import { EntryCallback, ReduceEntryCallback } from '../../types'; export abstract class IterableEntryBase { + // protected constructor(options?: IterableEntryBaseOptions) { + // if (options) { + // const { toEntryFn } = options; + // if (typeof toEntryFn === 'function') this._toEntryFn = toEntryFn + // else throw new TypeError('toEntryFn must be a function type'); + // } + // } + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -8,6 +16,16 @@ export abstract class IterableEntryBase { abstract get size(): number; + // protected _toEntryFn?: (rawElement: R) => BTNEntry; + // + // /** + // * The function returns the value of the _toEntryFn property. + // * @returns The function being returned is `this._toEntryFn`. + // */ + // get toEntryFn() { + // return this._toEntryFn; + // } + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -285,6 +303,13 @@ export abstract class IterableEntryBase { * Time Complexity: O(n) * Space Complexity: O(n) */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The print function logs the elements of an array to the console. + */ print(): void { console.log([...this]); } @@ -301,219 +326,3 @@ export abstract class IterableEntryBase { protected abstract _getIterator(...args: any[]): IterableIterator<[K, V]>; } - -export abstract class IterableElementBase { - abstract get size(): number; - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The function is an implementation of the Symbol.iterator method that returns an IterableIterator. - * @param {any[]} args - The `args` parameter in the code snippet represents a rest parameter. It - * allows the function to accept any number of arguments as an array. In this case, the `args` - * parameter is used to pass any number of arguments to the `_getIterator` method. - */ - * [Symbol.iterator](...args: any[]): IterableIterator { - yield* this._getIterator(...args); - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The function returns an iterator that yields all the values in the object. - */ - * values(): IterableIterator { - for (const item of this) { - yield item; - } - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `every` function checks if every element in the array satisfies a given predicate. - * @param predicate - The `predicate` parameter is a callback function that takes three arguments: - * the current element being processed, its index, and the array it belongs to. It should return a - * boolean value indicating whether the element satisfies a certain condition or not. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `predicate` function. If `thisArg` is - * @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 { - let index = 0; - for (const item of this) { - if (!predicate.call(thisArg, item, index++, this)) { - return false; - } - } - return true; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The "some" function checks if at least one element in a collection satisfies a given predicate. - * @param predicate - The `predicate` parameter is a callback function that takes three arguments: - * `value`, `index`, and `array`. It should return a boolean value indicating whether the current - * element satisfies the condition. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided, - * it will be passed as the `this` value to the `predicate` function. If `thisArg - * @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 { - let index = 0; - for (const item of this) { - if (predicate.call(thisArg, item, index++, this)) { - return true; - } - } - return false; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `forEach` function iterates over each element in an array-like object and calls a callback - * function for each element. - * @param callbackfn - The callbackfn 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 that forEach was called upon. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * 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 { - let index = 0; - for (const item of this) { - callbackfn.call(thisArg, item, index++, this); - } - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * 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 - * 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. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * 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 - * @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 { - let index = 0; - for (const item of this) { - if (callbackfn.call(thisArg, item, index++, this)) return item; - } - - return; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The function checks if a given element exists in a collection. - * @param {E} element - The parameter "element" is of type E, which means it can be any type. It - * represents the element that we want to check for existence in the collection. - * @returns a boolean value. It returns true if the element is found in the collection, and false - * otherwise. - */ - has(element: E): boolean { - for (const ele of this) { - if (ele === element) return true; - } - return false; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `reduce` function iterates over the elements of an array-like object and applies a callback - * function to reduce them into a single value. - * @param callbackfn - The callbackfn parameter is a function that will be called for each element in - * the array. It takes four arguments: - * @param {U} initialValue - The initialValue parameter is the initial value of the accumulator. It - * is the value that the accumulator starts with before the reduction operation begins. - * @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; - let index = 0; - for (const item of this) { - accumulator = callbackfn(accumulator, item as E, index++, this); - } - return accumulator; - } - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - print(): void { - console.log([...this]); - } - - abstract isEmpty(): boolean; - - abstract clear(): void; - - abstract clone(): C; - - abstract map(...args: any[]): any; - - abstract filter(...args: any[]): any; - - protected abstract _getIterator(...args: any[]): IterableIterator; -} diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index cd25982..54982b2 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -158,6 +158,7 @@ export class BinaryTree< const { iterationType, toEntryFn } = options; if (iterationType) this.iterationType = iterationType; if (typeof toEntryFn === 'function') this._toEntryFn = toEntryFn; + else if (toEntryFn) throw TypeError('toEntryFn must be a function type'); } if (keysOrNodesOrEntriesOrRawElements) this.addMany(keysOrNodesOrEntriesOrRawElements); diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index fd5ac19..e040c06 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -270,8 +270,8 @@ export class HashMap extends IterableEntryBase(callbackfn: EntryCallback, thisArg?: any): HashMap { - const resultMap = new HashMap(); + map(callbackfn: EntryCallback, thisArg?: any): HashMap { + const resultMap = new HashMap(); let index = 0; for (const [key, value] of this) { resultMap.set(key, callbackfn.call(thisArg, value, key, index++, this)); @@ -898,8 +898,8 @@ export class LinkedHashMap extends IterableEntryBa * @returns a new `LinkedHashMap` object with the values mapped according to the provided callback * function. */ - map(callback: EntryCallback, thisArg?: any): LinkedHashMap { - const mappedMap = new LinkedHashMap(); + map(callback: EntryCallback, thisArg?: any): LinkedHashMap { + const mappedMap = new LinkedHashMap(); let index = 0; for (const [key, value] of this) { const newValue = callback.call(thisArg, value, key, index, this); diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index f596ba5..70f6655 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -20,7 +20,7 @@ import { IterableElementBase } from '../base'; * 7. Efficient Sorting Algorithms: For example, heap sort. Heap sort uses the properties of a heap to sort elements. * 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prime's minimum-spanning tree algorithm, which use heaps to improve performance. */ -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 @@ -35,16 +35,16 @@ export class Heap extends IterableElementBase { * order of elements in the heap. */ constructor(elements: Iterable | Iterable = [], options?: HeapOptions) { - super(); + super(options); + if (options) { - const { comparator, toElementFn } = options; + const { comparator } = options; if (comparator) this._comparator = comparator; - if (toElementFn) this._toElementFn = toElementFn; } if (elements) { for (const el of elements) { - if (this._toElementFn) this.add(this._toElementFn(el as R)); + if (this.toElementFn) this.add(this.toElementFn(el as R)); else this.add(el as E); } } @@ -60,12 +60,6 @@ export class Heap extends IterableElementBase { return this._elements; } - protected _toElementFn?: (rawElement: R) => E; - - get toElementFn() { - return this._toElementFn; - } - /** * Get the size (number of elements) of the heap. */ @@ -132,12 +126,6 @@ export class Heap extends IterableElementBase { return this.elements[0]; } - /** - * Time Complexity: O(log n) - * Space Complexity: O(1) - * where n is the number of elements in the heap. - */ - /** * Check if the heap is empty. * @returns True if the heap is empty, otherwise false. @@ -146,12 +134,6 @@ export class Heap extends IterableElementBase { return this.size === 0; } - /** - * Time Complexity: O(log n) - * Space Complexity: O(1) - * where n is the number of elements in the heap. - */ - /** * Reset the elements of the heap. Make the elements empty. */ @@ -159,11 +141,6 @@ export class Heap extends IterableElementBase { this._elements = []; } - /** - * Time Complexity: O(1) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -214,11 +191,6 @@ export class Heap extends IterableElementBase { return true; } - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - /** * Time Complexity: O(n) * Space Complexity: O(log n) @@ -256,11 +228,6 @@ export class Heap extends IterableElementBase { return result; } - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -272,12 +239,6 @@ export class Heap extends IterableElementBase { return [...this.elements]; } - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * The worst-case O(n) This is because, in the worst case, the element to be deleted is located at the end of the heap (not the root), and after deletion, we may need to reorganize the elements by performing a sinkDown operation. - */ - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -285,18 +246,10 @@ export class Heap extends IterableElementBase { * Clone the heap, creating a new heap with the same elements. * @returns A new Heap instance containing the same elements. */ - clone(): Heap { - const clonedHeap = new Heap([], { comparator: this.comparator }); - clonedHeap._elements = [...this.elements]; - return clonedHeap; + clone(): Heap { + return new Heap(this, { comparator: this.comparator, toElementFn: this.toElementFn }); } - /** - * Time Complexity: O(n) - * Space Complexity: O(log n) - * where log n is the height of the heap. - */ - /** * Time Complexity: O(n log n) * Space Complexity: O(n) @@ -306,19 +259,14 @@ export class Heap extends IterableElementBase { */ sort(): E[] { const visitedNode: E[] = []; - const cloned = this.clone(); + const cloned = new Heap(this, { comparator: this.comparator }); while (cloned.size !== 0) { const top = cloned.poll(); - if (top) visitedNode.push(top); + if (top !== undefined) visitedNode.push(top); } return visitedNode; } - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - /** * Time Complexity: O(n log n) * Space Complexity: O(n) @@ -331,11 +279,6 @@ export class Heap extends IterableElementBase { return results; } - /** - * Time Complexity: O(n) - * Space Complexity: O(n) - */ - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -352,8 +295,8 @@ 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 { - const filteredList = new 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) { if (callback.call(thisArg, current, index, this)) { @@ -367,30 +310,31 @@ export class Heap extends IterableElementBase { /** * Time Complexity: O(n log n) * Space Complexity: O(n) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(n) * * The `map` function creates a new heap by applying a callback function to each element of the * original heap. - * @param callback - The callback parameter is a function that will be called for each element in the - * original heap. It takes three arguments: the current element, the index of the current element, - * and the original heap itself. The callback function should return a value of type T, which will be - * added to the mapped heap. - * @param comparator - The `comparator` parameter is a function that is used to compare elements in - * the heap. It takes two arguments, `a` and `b`, and returns a negative number if `a` is less than - * `b`, a positive number if `a` is greater than `b`, or + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to - * specify the value of `this` within the callback function. It is used when you want to bind a - * specific object as the context for the callback function. If `thisArg` is not provided, - * `undefined` is used as - * @returns a new instance of the Heap class, which is created using the mapped elements from the - * original Heap. + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `Heap` class with the mapped elements. */ - map(callback: ElementCallback, comparator: Comparator, thisArg?: any): Heap { - const mappedHeap: Heap = new Heap([], { comparator: comparator }); + map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): Heap { + const mappedHeap: Heap = new Heap([], { comparator, toElementFn }); let index = 0; for (const el of this) { mappedHeap.add(callback.call(thisArg, el, index, this)); @@ -429,11 +373,6 @@ export class Heap extends IterableElementBase { } } - /** - * Time Complexity: O(log n) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(log n) * Space Complexity: O(1) @@ -454,11 +393,6 @@ export class Heap extends IterableElementBase { return true; } - /** - * Time Complexity: O(log n) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(log n) * Space Complexity: O(1) @@ -580,11 +514,6 @@ export class FibonacciHeap { this._size = 0; } - /** - * Time Complexity: O(1) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -597,11 +526,6 @@ export class FibonacciHeap { return this.push(element); } - /** - * Time Complexity: O(1) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -624,11 +548,6 @@ export class FibonacciHeap { return this; } - /** - * Time Complexity: O(1) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(1) * Space Complexity: O(1) diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index 9a2621f..f61c1c8 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Kirk Qi * @license MIT License */ -import type { HeapOptions } from '../../types'; +import type { Comparator, ElementCallback, HeapOptions } from '../../types'; import { Heap } from './heap'; /** @@ -18,7 +18,7 @@ import { Heap } from './heap'; * 7. Efficient Sorting Algorithms: For example, heap sort. Heap sort uses the properties of a heap to sort elements. * 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prim's minimum-spanning tree algorithm, which use heaps to improve performance. */ -export class MaxHeap extends Heap { +export class MaxHeap extends Heap { constructor(elements: Iterable | Iterable = [], options?: HeapOptions) { super(elements, { comparator: (a: E, b: E): number => { @@ -34,4 +34,78 @@ export class MaxHeap extends Heap { ...options }); } + + /** + * The `clone` function returns a new instance of the `MaxHeap` class with the same properties as the + * current instance. + * @returns The `clone()` method is returning a new instance of the `MaxHeap` class with the same + * properties as the current instance. + */ + override clone(): MaxHeap { + return new MaxHeap(this, { comparator: this.comparator, toElementFn: this.toElementFn }); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new MaxHeap object containing elements that pass a given callback + * function. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: the current element, the index of the current element, and the + * heap itself. The callback function should return a boolean value indicating whether the current + * element should be included in the filtered list + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is + * @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 { + const filteredList = new MaxHeap([], { toElementFn: this.toElementFn, comparator: this.comparator }); + let index = 0; + for (const current of this) { + if (callback.call(thisArg, current, index, this)) { + filteredList.add(current); + } + index++; + } + return filteredList; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `map` function creates a new heap by applying a callback function to each element of the + * original heap. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `MaxHeap` class with the mapped elements. + */ + override map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): MaxHeap { + const mappedHeap: MaxHeap = new MaxHeap([], { comparator, toElementFn }); + let index = 0; + for (const el of this) { + mappedHeap.add(callback.call(thisArg, el, index, this)); + index++; + } + return mappedHeap; + } } diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index f76713a..3a0af05 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -5,21 +5,95 @@ * @copyright Copyright (c) 2022 Kirk Qi * @license MIT License */ -import type { HeapOptions } from '../../types'; +import type { Comparator, ElementCallback, HeapOptions } from '../../types'; import { Heap } from './heap'; /** * 1. Complete Binary Tree: Heaps are typically complete binary trees, meaning every level is fully filled except possibly for the last level, which has nodes as far left as possible. - * 2. Heap Properties: The value of each parent node is less than or equal to the value of its children. + * 2. MinHeap Properties: The value of each parent node is less than or equal to the value of its children. * 3. Root Node Access: In a heap, the largest element (in a max heap) or the smallest element (in a min heap) is always at the root of the tree. * 4. Efficient Insertion and Deletion: Due to its structure, a heap allows for insertion and deletion operations in logarithmic time (O(log n)). * 5. Managing Dynamic Data Sets: Heaps effectively manage dynamic data sets, especially when frequent access to the largest or smallest elements is required. * 6. Non-linear Search: While a heap allows rapid access to its largest or smallest element, it is less efficient for other operations, such as searching for a specific element, as it is not designed for these tasks. - * 7. Efficient Sorting Algorithms: For example, heap sort. Heap sort uses the properties of a heap to sort elements. + * 7. Efficient Sorting Algorithms: For example, heap sort. MinHeap sort uses the properties of a heap to sort elements. * 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prim's minimum spanning tree algorithm, which use heaps to improve performance. */ -export class MinHeap extends Heap { +export class MinHeap extends Heap { constructor(elements: Iterable | Iterable = [], options?: HeapOptions) { super(elements, options); } + + /** + * The `clone` function returns a new instance of the `MinHeap` class with the same comparator and + * toElementFn as the original instance. + * @returns The `clone()` method is returning a new instance of the `MinHeap` class with the same + * properties as the current instance. + */ + override clone(): MinHeap { + return new MinHeap(this, { comparator: this.comparator, toElementFn: this.toElementFn }); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new MinHeap object containing elements that pass a given callback + * function. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: the current element, the index of the current element, and the + * heap itself. The callback function should return a boolean value indicating whether the current + * element should be included in the filtered list + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is + * @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 { + const filteredList = new MinHeap([], { toElementFn: this.toElementFn, comparator: this.comparator }); + let index = 0; + for (const current of this) { + if (callback.call(thisArg, current, index, this)) { + filteredList.add(current); + } + index++; + } + return filteredList; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `map` function creates a new heap by applying a callback function to each element of the + * original heap. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `MinHeap` class with the mapped elements. + */ + override map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): MinHeap { + const mappedHeap: MinHeap = new MinHeap([], { comparator, toElementFn }); + let index = 0; + for (const el of this) { + mappedHeap.add(callback.call(thisArg, el, index, this)); + index++; + } + return mappedHeap; + } } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 4a29580..9da1c26 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type { ElementCallback } from '../../types'; +import type { DoublyLinkedListOptions, ElementCallback } from '../../types'; import { IterableElementBase } from '../base'; export class DoublyLinkedListNode { @@ -87,21 +87,17 @@ export class DoublyLinkedListNode { * 3. No Centralized Index: Unlike arrays, elements in a linked list are not stored contiguously, so there is no centralized index. Accessing elements in a linked list typically requires traversing from the head or tail node. * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays. */ -export class DoublyLinkedList extends IterableElementBase { - /** - * The constructor initializes a linked list with optional elements. - * @param elements - The `elements` parameter is an optional iterable object that contains the - * initial elements to be added to the data structure. It defaults to an empty array if no elements - * are provided. - */ - constructor(elements: Iterable = []) { - super(); +export class DoublyLinkedList extends IterableElementBase> { + constructor(elements: Iterable | Iterable = [], options?: DoublyLinkedListOptions) { + super(options); this._head = undefined; this._tail = undefined; this._size = 0; if (elements) { for (const el of elements) { - this.push(el); + if (this.toElementFn) { + this.push(this.toElementFn(el as R)); + } else this.push(el as E); } } } @@ -729,8 +725,8 @@ export class DoublyLinkedList extends IterableElementBase { * @returns The `clone()` method is returning a new instance of the `DoublyLinkedList` class, which * is a copy of the original list. */ - clone(): DoublyLinkedList { - return new DoublyLinkedList(this.values()); + clone(): DoublyLinkedList { + return new DoublyLinkedList(this); } /** @@ -755,8 +751,8 @@ export class DoublyLinkedList extends IterableElementBase { * @returns The `filter` method is returning a new `DoublyLinkedList` object that contains the * elements that pass the filter condition specified by the `callback` function. */ - filter(callback: ElementCallback, thisArg?: any): DoublyLinkedList { - const filteredList = new DoublyLinkedList(); + filter(callback: ElementCallback>, thisArg?: any): DoublyLinkedList { + const filteredList = new DoublyLinkedList([], { toElementFn: this.toElementFn }); let index = 0; for (const current of this) { if (callback.call(thisArg, current, index, this)) { @@ -773,24 +769,28 @@ export class DoublyLinkedList extends IterableElementBase { */ /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `map` function creates a new DoublyLinkedList by applying a callback function to each element - * in the original list. + * The `map` function takes a callback function and returns a new DoublyLinkedList with the results + * of applying the callback to each element in the original list. * @param callback - The callback parameter is a function that will be called for each element in the - * DoublyLinkedList. It takes three arguments: the current element, the index of the current element, - * and the DoublyLinkedList itself. The callback function should return a value that will be added to - * the new DoublyLinkedList that - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns The `map` function is returning a new `DoublyLinkedList` object that contains the results - * of applying the provided `callback` function to each element in the original `DoublyLinkedList` - * object. + * original DoublyLinkedList. It takes three arguments: current (the current element being + * processed), index (the index of the current element), and this (the original DoublyLinkedList). + * The callback function should return a value of type + * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to + * convert the raw element (`RR`) to the desired element type (`T`). It takes the raw element as + * input and returns the converted element. If this parameter is not provided, the raw element will + * be used as is. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `DoublyLinkedList` class with elements of type `T` and `RR`. */ - map(callback: ElementCallback, thisArg?: any): DoublyLinkedList { - const mappedList = new DoublyLinkedList(); + map( + callback: ElementCallback>, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): DoublyLinkedList { + const mappedList = new DoublyLinkedList([], { toElementFn }); let index = 0; for (const current of this) { mappedList.push(callback.call(thisArg, current, index, this)); diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 65cafb3..70de1b9 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type { ElementCallback } from '../../types'; +import type { ElementCallback, SinglyLinkedListOptions } from '../../types'; import { IterableElementBase } from '../base'; export class SinglyLinkedListNode { @@ -59,17 +59,17 @@ export class SinglyLinkedListNode { } } -export class SinglyLinkedList extends IterableElementBase { - /** - * The constructor initializes a new instance of a class with an optional iterable of elements. - * @param elements - The `elements` parameter is an optional iterable object that contains the - * initial elements to be added to the instance of the class. If no `elements` are provided, an empty - * array will be used as the default value. - */ - constructor(elements: Iterable = []) { - super(); +export class SinglyLinkedList extends IterableElementBase> { + constructor(elements: Iterable | Iterable = [], options?: SinglyLinkedListOptions) { + super(options); if (elements) { - for (const el of elements) this.push(el); + for (const el of elements) { + if (this.toElementFn) { + this.push(this.toElementFn(el as R)); + } else { + this.push(el as E); + } + } } } @@ -673,8 +673,8 @@ export class SinglyLinkedList extends IterableElementBase { * @returns The `clone()` method is returning a new instance of the `SinglyLinkedList` class, which * is a clone of the original list. */ - clone(): SinglyLinkedList { - return new SinglyLinkedList(this.values()); + clone(): SinglyLinkedList { + return new SinglyLinkedList(this, { toElementFn: this.toElementFn }); } /** @@ -699,8 +699,8 @@ export class SinglyLinkedList extends IterableElementBase { * @returns The `filter` method is returning a new `SinglyLinkedList` object that contains the * elements that pass the filter condition specified by the `callback` function. */ - filter(callback: ElementCallback, thisArg?: any): SinglyLinkedList { - const filteredList = new SinglyLinkedList(); + filter(callback: ElementCallback>, thisArg?: any): SinglyLinkedList { + const filteredList = new SinglyLinkedList([], { toElementFn: this.toElementFn }); let index = 0; for (const current of this) { if (callback.call(thisArg, current, index, this)) { @@ -715,22 +715,30 @@ export class SinglyLinkedList extends IterableElementBase { * Time Complexity: O(n) * Space Complexity: O(n) */ + /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `map` function creates a new SinglyLinkedList by applying a callback function to each element - * of the original list. + * The `map` function takes a callback function and returns a new SinglyLinkedList with the results + * of applying the callback to each element in the original list. * @param callback - The `callback` parameter is a function that will be called for each element in - * the linked list. It takes three arguments: - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns The `map` function is returning a new `SinglyLinkedList` object that contains the results - * of applying the provided `callback` function to each element in the original list. + * the original list. It takes three arguments: `current` (the current element being processed), + * `index` (the index of the current element), and `this` (the original list). It should return a + * value + * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to + * convert the raw element (`RR`) to the desired element type (`T`). It takes the raw element as + * input and returns the converted element. If this parameter is not provided, the raw element will + * be used as is. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `SinglyLinkedList` class with the mapped elements. */ - map(callback: ElementCallback, thisArg?: any): SinglyLinkedList { - const mappedList = new SinglyLinkedList(); + map( + callback: ElementCallback>, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): SinglyLinkedList { + const mappedList = new SinglyLinkedList([], { toElementFn }); let index = 0; for (const current of this) { mappedList.push(callback.call(thisArg, current, index, this)); diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 05b52dd..2464a1b 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -5,10 +5,10 @@ * @copyright Copyright (c) 2022 Kirk Qi * @license MIT License */ -import type { PriorityQueueOptions } from '../../types'; +import type { Comparator, ElementCallback, PriorityQueueOptions } from '../../types'; import { PriorityQueue } from './priority-queue'; -export class MaxPriorityQueue extends PriorityQueue { +export class MaxPriorityQueue extends PriorityQueue { /** * The constructor initializes a PriorityQueue with optional elements and options, including a * comparator function. @@ -34,4 +34,84 @@ export class MaxPriorityQueue extends PriorityQueue { ...options }); } + + /** + * The `clone` function returns a new instance of the `MaxPriorityQueue` class with the same + * comparator and toElementFn as the current instance. + * @returns The method is returning a new instance of the MaxPriorityQueue class with the same + * comparator and toElementFn as the current instance. + */ + override clone(): MaxPriorityQueue { + return new MaxPriorityQueue(this, { comparator: this.comparator, toElementFn: this.toElementFn }); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new MaxPriorityQueue object containing elements that pass a given callback + * function. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: the current element, the index of the current element, and the + * heap itself. The callback function should return a boolean value indicating whether the current + * element should be included in the filtered list + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is + * @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 { + const filteredPriorityQueue = new MaxPriorityQueue([], { + toElementFn: this.toElementFn, + comparator: this.comparator + }); + let index = 0; + for (const current of this) { + if (callback.call(thisArg, current, index, this)) { + filteredPriorityQueue.add(current); + } + index++; + } + return filteredPriorityQueue; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `map` function creates a new heap by applying a callback function to each element of the + * original heap. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `MaxPriorityQueue` class with the mapped elements. + */ + override map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): MaxPriorityQueue { + const mappedPriorityQueue = new MaxPriorityQueue([], { comparator, toElementFn }); + let index = 0; + for (const el of this) { + mappedPriorityQueue.add(callback.call(thisArg, el, index, this)); + index++; + } + return mappedPriorityQueue; + } } diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 33edf7d..a7f3cf0 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -5,10 +5,10 @@ * @copyright Copyright (c) 2022 Kirk Qi * @license MIT License */ -import type { PriorityQueueOptions } from '../../types'; +import type { Comparator, ElementCallback, PriorityQueueOptions } from '../../types'; import { PriorityQueue } from './priority-queue'; -export class MinPriorityQueue extends PriorityQueue { +export class MinPriorityQueue extends PriorityQueue { /** * The constructor initializes a PriorityQueue with optional elements and options, including a * comparator function. @@ -23,4 +23,84 @@ export class MinPriorityQueue extends PriorityQueue { constructor(elements: Iterable | Iterable = [], options?: PriorityQueueOptions) { super(elements, options); } + + /** + * The `clone` function returns a new instance of the `MinPriorityQueue` class with the same + * comparator and toElementFn as the original instance. + * @returns The method is returning a new instance of the `MinPriorityQueue` class with the same + * properties as the current instance. + */ + override clone(): MinPriorityQueue { + return new MinPriorityQueue(this, { comparator: this.comparator, toElementFn: this.toElementFn }); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new MinPriorityQueue object containing elements that pass a given callback + * function. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: the current element, the index of the current element, and the + * heap itself. The callback function should return a boolean value indicating whether the current + * element should be included in the filtered list + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is + * @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 { + const filteredPriorityQueue = new MinPriorityQueue([], { + toElementFn: this.toElementFn, + comparator: this.comparator + }); + let index = 0; + for (const current of this) { + if (callback.call(thisArg, current, index, this)) { + filteredPriorityQueue.add(current); + } + index++; + } + return filteredPriorityQueue; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `map` function creates a new heap by applying a callback function to each element of the + * original heap. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `MinPriorityQueue` class with the mapped elements. + */ + override map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): MinPriorityQueue { + const mappedPriorityQueue: MinPriorityQueue = new MinPriorityQueue([], { comparator, toElementFn }); + let index = 0; + for (const el of this) { + mappedPriorityQueue.add(callback.call(thisArg, el, index, this)); + index++; + } + return mappedPriorityQueue; + } } diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 11c68a8..0d48814 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Kirk Qi * @license MIT License */ -import type { PriorityQueueOptions } from '../../types'; +import type { Comparator, ElementCallback, PriorityQueueOptions } from '../../types'; import { Heap } from '../heap'; /** @@ -28,4 +28,81 @@ export class PriorityQueue extends Heap { constructor(elements: Iterable | Iterable = [], options?: PriorityQueueOptions) { super(elements, options); } + + /** + * The `clone` function returns a new instance of the `PriorityQueue` class with the same comparator + * and toElementFn as the original instance. + * @returns The method is returning a new instance of the `PriorityQueue` class with the same + * elements and properties as the current instance. + */ + override clone(): PriorityQueue { + return new PriorityQueue(this, { comparator: this.comparator, toElementFn: this.toElementFn }); + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * The `filter` function creates a new PriorityQueue object containing elements that pass a given callback + * function. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: the current element, the index of the current element, and the + * heap itself. The callback function should return a boolean value indicating whether the current + * element should be included in the filtered list + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is + * @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 { + const filteredPriorityQueue = new PriorityQueue([], { + toElementFn: this.toElementFn, + comparator: this.comparator + }); + let index = 0; + for (const current of this) { + if (callback.call(thisArg, current, index, this)) { + filteredPriorityQueue.add(current); + } + index++; + } + return filteredPriorityQueue; + } + + /** + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * The `map` function creates a new heap by applying a callback function to each element of the + * original heap. + * @param callback - The `callback` parameter is a function that will be called for each element in + * the heap. It takes three arguments: `el` (the current element), `index` (the index of the current + * element), and `this` (the heap itself). The callback function should return a value of + * @param comparator - The `comparator` parameter is a function that defines the order of the + * elements in the heap. It takes two elements `a` and `b` as arguments and returns a negative number + * if `a` should be placed before `b`, a positive number if `a` should be placed after + * @param [toElementFn] - The `toElementFn` parameter is an optional function that converts the raw + * element `RR` to the desired type `T`. It takes a single argument `rawElement` of type `RR` and + * returns a value of type `T`. This function is used to transform the elements of the original + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new instance of the `PriorityQueue` class with the mapped elements. + */ + override map( + callback: ElementCallback>, + comparator: Comparator, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): PriorityQueue { + const mappedPriorityQueue: PriorityQueue = new PriorityQueue([], { comparator, toElementFn }); + let index = 0; + for (const el of this) { + mappedPriorityQueue.add(callback.call(thisArg, el, index, this)); + index++; + } + return mappedPriorityQueue; + } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 530f3c4..edabb88 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -16,9 +16,9 @@ import { calcMinUnitsRequired, rangeCheck } from '../../utils'; * 4. Efficiency: Adding and removing elements at both ends of a deque is usually very fast. However, when the dynamic array needs to expand, it may involve copying the entire array to a larger one, and this operation has a time complexity of O(n). * 5. Performance jitter: Deque may experience performance jitter, but DoublyLinkedList will not */ -export class Deque extends IterableElementBase { +export class Deque extends IterableElementBase> { /** - * The constructor initializes a Deque object with an optional iterable of elements and options. + * 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 * elements to be added to the deque. It can also be an object with a `length` or `size` property * that represents the number of elements in the iterable object. If no elements are provided, an @@ -28,8 +28,8 @@ export class Deque extends IterableElementBase { * which determines the size of each bucket in the deque. If the `bucketSize` option is not provided * or is not a number */ - constructor(elements: IterableWithSizeOrLength = [], options?: DequeOptions) { - super(); + constructor(elements: IterableWithSizeOrLength | IterableWithSizeOrLength = [], options?: DequeOptions) { + super(options); if (options) { const { bucketSize } = options; @@ -53,8 +53,12 @@ export class Deque extends IterableElementBase { this._bucketFirst = this._bucketLast = (this._bucketCount >> 1) - (needBucketNum >> 1); this._firstInBucket = this._lastInBucket = (this._bucketSize - (_size % this._bucketSize)) >> 1; - for (const element of elements) { - this.push(element); + for (const el of elements) { + if (this.toElementFn) { + this.push(this.toElementFn(el as R)); + } else { + this.push(el as E); + } } } @@ -747,8 +751,8 @@ export class Deque extends IterableElementBase { * @returns The `clone()` method is returning a new instance of the `Deque` class with the same * elements as the original deque (`this`) and the same bucket size. */ - clone(): Deque { - return new Deque([...this], { bucketSize: this.bucketSize }); + clone(): Deque { + return new Deque(this, { bucketSize: this.bucketSize, toElementFn: this.toElementFn }); } /** @@ -772,8 +776,8 @@ export class Deque extends IterableElementBase { * @returns The `filter` method is returning a new `Deque` object that contains the elements that * satisfy the given predicate function. */ - filter(predicate: ElementCallback, thisArg?: any): Deque { - const newDeque = new Deque([], { bucketSize: this._bucketSize }); + filter(predicate: ElementCallback>, thisArg?: any): Deque { + const newDeque = new Deque([], { bucketSize: this._bucketSize, toElementFn: this.toElementFn }); let index = 0; for (const el of this) { if (predicate.call(thisArg, el, index, this)) { @@ -788,21 +792,28 @@ export class Deque extends IterableElementBase { * Time Complexity: O(n) * Space Complexity: O(n) */ + /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * - * The `map` function creates a new Deque by applying a callback function to each element of the - * original Deque. - * @param callback - The `callback` parameter is a function that will be called for each element in - * the deque. It takes three arguments: - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns a new Deque object with the mapped values. + * 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 will be called for each element in the + * deque. It takes three arguments: the current element, the index of the element, and the deque + * itself. It should return a value of type EM. + * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to + * transform the raw element (`RM`) into a new element (`EM`) before adding it to the new deque. If + * provided, this function will be called for each raw element in the original deque. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new Deque object with elements of type EM and raw elements of type RM. */ - map(callback: ElementCallback, thisArg?: any): Deque { - const newDeque = new Deque([], { bucketSize: this._bucketSize }); + 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) { newDeque.push(callback.call(thisArg, el, index, this)); diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 3dc3849..fe49ae1 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -3,7 +3,7 @@ * @copyright Tyler Zeng * @class */ -import type { ElementCallback } from '../../types'; +import type { ElementCallback, QueueOptions } from '../../types'; import { IterableElementBase } from '../base'; import { SinglyLinkedList } from '../linked-list'; @@ -16,17 +16,14 @@ 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 { - /** - * The constructor initializes an instance of a class with an optional array of elements and sets the offset to 0. - * @param {E[]} [elements] - The `elements` parameter is an optional array of elements of type `E`. If provided, it - * will be used to initialize the `_elements` property of the class. If not provided, the `_elements` property will be - * initialized as an empty array. - */ - constructor(elements: Iterable = []) { - super(); +export class Queue extends IterableElementBase> { + constructor(elements: Iterable | Iterable = [], options?: QueueOptions) { + super(options); if (elements) { - for (const el of elements) this.push(el); + for (const el of elements) { + if (this.toElementFn) this.push(this.toElementFn(el as R)); + else this.push(el as E); + } } } @@ -190,7 +187,7 @@ export class Queue extends IterableElementBase { * @param index */ at(index: number): E | undefined { - return this.elements[index]; + return this.elements[index + this._offset]; } /** @@ -254,8 +251,8 @@ export class Queue extends IterableElementBase { * The `clone()` function returns a new Queue object with the same elements as the original Queue. * @returns The `clone()` method is returning a new instance of the `Queue` class. */ - clone(): Queue { - return new Queue(this.elements.slice(this.offset)); + clone(): Queue { + return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn }); } /** @@ -279,8 +276,8 @@ export class Queue extends IterableElementBase { * @returns The `filter` method is returning a new `Queue` object that contains the elements that * satisfy the given predicate function. */ - filter(predicate: ElementCallback, thisArg?: any): Queue { - const newDeque = new Queue([]); + filter(predicate: ElementCallback>, thisArg?: any): Queue { + const newDeque = new Queue([], { toElementFn: this.toElementFn }); let index = 0; for (const el of this) { if (predicate.call(thisArg, el, index, this)) { @@ -296,22 +293,12 @@ export class Queue extends IterableElementBase { * 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 queue, - * returning a new queue with the results. - * @param callback - The callback parameter is a function that will be called for each element in the - * queue. It takes three arguments: the current element, the index of the current element, and the - * queue itself. The callback function should return a new value that will be added to the new queue. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns The `map` function is returning a new `Queue` object with the transformed elements. - */ - map(callback: ElementCallback, thisArg?: any): Queue { - const newDeque = new Queue([]); + map( + callback: ElementCallback>, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): Queue { + const newDeque = new Queue([], { toElementFn }); let index = 0; for (const el of this) { newDeque.push(callback.call(thisArg, el, index, this)); @@ -332,7 +319,7 @@ export class Queue extends IterableElementBase { * The function `_getIterator` returns an iterable iterator for the elements in the class. */ protected* _getIterator(): IterableIterator { - for (const item of this.elements) { + for (const item of this.elements.slice(this.offset)) { yield item; } } @@ -344,7 +331,7 @@ export class Queue extends IterableElementBase { * 3. Memory Usage: Since each element requires additional space to store a pointer to the next element, linked lists may use more memory compared to arrays. * 4. Frequent Enqueuing and Dequeuing Operations: If your application involves frequent enqueuing and dequeuing operations and is less concerned with random access, then LinkedListQueue is a good choice. */ -export class LinkedListQueue extends SinglyLinkedList { +export class LinkedListQueue extends SinglyLinkedList { /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -358,7 +345,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.values()); + override clone(): LinkedListQueue { + return new LinkedListQueue(this, { toElementFn: this.toElementFn }); } } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 9661a80..2c1c6bf 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type { ElementCallback } from '../../types'; +import type { ElementCallback, StackOptions } from '../../types'; import { IterableElementBase } from '../base'; /** @@ -16,17 +16,17 @@ 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 { - /** - * The constructor initializes an array of elements, which can be provided as an optional parameter. - * @param {E[]} [elements] - The `elements` parameter is an optional parameter of type `E[]`, which represents an array - * of elements of type `E`. It is used to initialize the `_elements` property of the class. If the `elements` parameter - * is provided and is an array, it is assigned to the `_elements - */ - constructor(elements: Iterable = []) { - super(); +export class Stack extends IterableElementBase> { + constructor(elements: Iterable | Iterable = [], options?: StackOptions) { + super(options); if (elements) { - for (const el of elements) this.push(el); + for (const el of elements) { + if (this.toElementFn) { + this.push(this.toElementFn(el as R)); + } else { + this.push(el as E); + } + } } } @@ -192,8 +192,8 @@ export class Stack extends IterableElementBase { * The `clone()` function returns a new `Stack` object with the same elements as the original stack. * @returns The `clone()` method is returning a new `Stack` object with a copy of the `_elements` array. */ - clone(): Stack { - return new Stack(this.elements.slice()); + clone(): Stack { + return new Stack(this, { toElementFn: this.toElementFn }); } /** @@ -217,8 +217,8 @@ export class Stack extends IterableElementBase { * @returns The `filter` method is returning a new `Stack` object that contains the elements that * satisfy the given predicate function. */ - filter(predicate: ElementCallback, thisArg?: any): Stack { - const newStack = new Stack(); + filter(predicate: ElementCallback>, thisArg?: any): Stack { + const newStack = new Stack([], { toElementFn: this.toElementFn }); let index = 0; for (const el of this) { if (predicate.call(thisArg, el, index, this)) { @@ -235,20 +235,25 @@ export class Stack extends IterableElementBase { */ /** - * Time Complexity: O(n) - * Space Complexity: O(n) - * * The `map` function takes a callback function and applies it to each element in the stack, * returning a new stack with the results. - * @param callback - The `callback` parameter is a function that will be called for each element in - * the stack. It takes three arguments: - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns The `map` method is returning a new `Stack` object. + * @param callback - The callback parameter is a function that will be called for each element in the + * stack. It takes three arguments: the current element, the index of the element, and the stack + * itself. It should return a new value that will be added to the new stack. + * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to + * transform the raw element (`RM`) into a new element (`EM`) before pushing it into the new stack. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new Stack object with elements of type EM and raw elements of type RM. */ - map(callback: ElementCallback, thisArg?: any): Stack { - const newStack = new Stack(); + map( + callback: ElementCallback>, + toElementFn?: (rawElement: RM) => EM, + thisArg?: any + ): Stack { + const newStack = new Stack([], { toElementFn }); let index = 0; for (const el of this) { newStack.push(callback.call(thisArg, el, index, this)); diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 6d2b551..8b2ddbf 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -93,21 +93,27 @@ export class TrieNode { * 10. IP Routing: Used in certain types of IP routing algorithms. * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data. */ -export class Trie extends IterableElementBase { +export class Trie extends IterableElementBase> { /** * The constructor function for the Trie class. * @param words: Iterable string Initialize the trie with a set of words * @param options?: TrieOptions Allow the user to pass in options for the trie * @return This */ - constructor(words: Iterable = [], options?: TrieOptions) { - super(); + constructor(words: Iterable | Iterable = [], options?: TrieOptions) { + super(options); if (options) { const { caseSensitive } = options; if (caseSensitive !== undefined) this._caseSensitive = caseSensitive; } if (words) { - for (const word of words) this.add(word); + for (const word of words) { + if (this.toElementFn) { + this.add(this.toElementFn(word as R)); + } else { + this.add(word as string); + } + } } } @@ -470,8 +476,8 @@ export class Trie extends IterableElementBase { * sensitivity as the original Trie. * @returns A new instance of the Trie class is being returned. */ - clone(): Trie { - return new Trie(this.values(), { caseSensitive: this.caseSensitive }); + clone(): Trie { + return new Trie(this, { caseSensitive: this.caseSensitive, toElementFn: this.toElementFn }); } /** @@ -493,8 +499,8 @@ 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 { - const results: Trie = new 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) { if (predicate.call(thisArg, word, index, this)) { @@ -514,17 +520,26 @@ export class Trie extends IterableElementBase { * Time Complexity: O(n) * Space Complexity: O(n) * - * The `map` function creates a new Trie by applying a callback function to each element in the Trie. + * The `map` function creates a new Trie by applying a callback function to each element in the + * current Trie. * @param callback - The callback parameter is a function that will be called for each element in the - * Trie. It takes three arguments: the current element in the Trie, the index of the current element, - * and the Trie itself. The callback function should return a new value for the element. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be - * passed as the `this` value to the `callback` function. If `thisArg` is - * @returns The `map` function is returning a new Trie object. + * Trie. It takes four arguments: + * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to + * convert the raw element (`RM`) into a string representation. This can be useful if the raw element + * is not already a string or if you want to customize how the element is converted into a string. If + * this parameter is + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the callback function. It is used to set the context or scope + * in which the callback function will be executed. If `thisArg` is provided, it will be used as the + * value of + * @returns a new Trie object. */ - map(callback: ElementCallback, thisArg?: any): Trie { - const newTrie = new Trie(); + map( + callback: ElementCallback>, + toElementFn?: (rawElement: RM) => string, + thisArg?: any + ): Trie { + const newTrie = new Trie([], { toElementFn, caseSensitive: this.caseSensitive }); let index = 0; for (const word of this) { newTrie.add(callback.call(thisArg, word, index, this)); diff --git a/src/types/data-structures/base/base.ts b/src/types/data-structures/base/base.ts index 785cea4..d34d962 100644 --- a/src/types/data-structures/base/base.ts +++ b/src/types/data-structures/base/base.ts @@ -1,7 +1,7 @@ import { IterableElementBase, IterableEntryBase } from '../../../data-structures'; export type EntryCallback = (value: V, key: K, index: number, container: IterableEntryBase) => R; -export type ElementCallback = (element: V, index: number, container: IterableElementBase) => R; +export type ElementCallback = (element: E, index: number, container: IterableElementBase) => RT; export type ReduceEntryCallback = ( accumulator: R, value: V, @@ -9,9 +9,17 @@ export type ReduceEntryCallback = ( index: number, container: IterableEntryBase ) => R; -export type ReduceElementCallback = ( - accumulator: R, - element: V, +export type ReduceElementCallback = ( + accumulator: RT, + element: E, index: number, - container: IterableElementBase -) => R; + container: IterableElementBase +) => RT; + +// export type IterableEntryBaseOptions = { + // toEntryFn?: (rawElement: R) => BTNEntry; +// }; + +export type IterableElementBaseOptions = { + toElementFn?: (rawElement: R) => E; +}; diff --git a/src/types/data-structures/heap/heap.ts b/src/types/data-structures/heap/heap.ts index 0469867..92c861a 100644 --- a/src/types/data-structures/heap/heap.ts +++ b/src/types/data-structures/heap/heap.ts @@ -1,6 +1,6 @@ import { Comparator } from '../../common'; +import { IterableElementBaseOptions } from '../base'; -export type HeapOptions = { +export type HeapOptions = IterableElementBaseOptions & { comparator?: Comparator; - toElementFn?: (rawElement: R) => E; }; 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 cb0ff5c..49b7f44 100644 --- a/src/types/data-structures/linked-list/doubly-linked-list.ts +++ b/src/types/data-structures/linked-list/doubly-linked-list.ts @@ -1 +1,3 @@ -export {}; +import { IterableElementBaseOptions } from '../base'; + +export type DoublyLinkedListOptions = IterableElementBaseOptions & {}; 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 cb0ff5c..c3e4c3e 100644 --- a/src/types/data-structures/linked-list/singly-linked-list.ts +++ b/src/types/data-structures/linked-list/singly-linked-list.ts @@ -1 +1,3 @@ -export {}; +import { IterableElementBaseOptions } from '../base'; + +export type SinglyLinkedListOptions = IterableElementBaseOptions & {}; diff --git a/src/types/data-structures/queue/deque.ts b/src/types/data-structures/queue/deque.ts index 8134e3e..e260eee 100644 --- a/src/types/data-structures/queue/deque.ts +++ b/src/types/data-structures/queue/deque.ts @@ -1 +1,3 @@ -export type DequeOptions = { bucketSize?: number }; +import { IterableElementBaseOptions } from '../base'; + +export type DequeOptions = { bucketSize?: number } & IterableElementBaseOptions; diff --git a/src/types/data-structures/queue/queue.ts b/src/types/data-structures/queue/queue.ts index cb0ff5c..3058185 100644 --- a/src/types/data-structures/queue/queue.ts +++ b/src/types/data-structures/queue/queue.ts @@ -1 +1,3 @@ -export {}; +import { IterableElementBaseOptions } from '../base'; + +export type QueueOptions = IterableElementBaseOptions & {}; diff --git a/src/types/data-structures/stack/stack.ts b/src/types/data-structures/stack/stack.ts index cb0ff5c..ec3b68c 100644 --- a/src/types/data-structures/stack/stack.ts +++ b/src/types/data-structures/stack/stack.ts @@ -1 +1,3 @@ -export {}; +import { IterableElementBaseOptions } from '../base'; + +export type StackOptions = IterableElementBaseOptions & {}; diff --git a/src/types/data-structures/trie/trie.ts b/src/types/data-structures/trie/trie.ts index bbdd970..f43a81a 100644 --- a/src/types/data-structures/trie/trie.ts +++ b/src/types/data-structures/trie/trie.ts @@ -1 +1,3 @@ -export type TrieOptions = { caseSensitive?: boolean }; +import { IterableElementBaseOptions } from '../base'; + +export type TrieOptions = { caseSensitive?: boolean } & IterableElementBaseOptions; diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 78beeef..009cc2b 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -88,6 +88,44 @@ describe('Heap Operation Test', () => { } }); + it('should object heap map & filter', function () { + const minHeap = new MinHeap<{ a: string; key: number }>( + [ + { key: 1, a: 'a1' }, + { key: 6, a: 'a6' }, + { key: 5, a: 'a5' }, + { key: 3, a: 'a3' }, + { key: 2, a: 'a2' }, + { key: 4, a: 'a4' }, + { key: 0, a: 'a0' } + ], + { comparator: (a, b) => a.key - b.key } + ); + + const mappedMinHeap = minHeap.map( + item => item.key, + (a, b) => a - b + ); + expect(mappedMinHeap.peek()).toBe(0); + expect(mappedMinHeap.sort()).toEqual([0, 1, 2, 3, 4, 5, 6]); + + const mappedToElementFnMinHeap = minHeap.map( + item => item.key.toString(), + (a, b) => Number(a) - Number(b), + rawElement => rawElement.id + ); + expect(mappedToElementFnMinHeap.peek()).toBe('0'); + expect(mappedToElementFnMinHeap.sort()).toEqual(['0', '1', '2', '3', '4', '5', '6']); + + const filteredHeap = minHeap.filter(item => item.key > 3); + expect(filteredHeap.peek()).toEqual({ a: 'a4', key: 4 }); + expect(filteredHeap.sort()).toEqual([ + { a: 'a4', key: 4 }, + { a: 'a5', key: 5 }, + { a: 'a6', key: 6 } + ]); + }); + it('should object heap', () => { const heap = new Heap<{ rawItem: { id: number } }>( [ diff --git a/test/unit/data-structures/heap/max-heap.test.ts b/test/unit/data-structures/heap/max-heap.test.ts index c8dc654..4df04a4 100644 --- a/test/unit/data-structures/heap/max-heap.test.ts +++ b/test/unit/data-structures/heap/max-heap.test.ts @@ -5,7 +5,7 @@ describe('MaxHeap', () => { let maxHeap: MaxHeap; beforeEach(() => { - maxHeap = new MaxHeap([], { comparator: numberComparator }); + maxHeap = new MaxHeap([], { comparator: numberComparator }); }); it('add and poll elements in descending order', () => { @@ -49,4 +49,47 @@ describe('MaxHeap', () => { maxHeap.poll(); expect(maxHeap.isEmpty()).toBe(true); }); + + it('should object heap map & filter', function () { + const maxHeap = new MaxHeap<{ a: string; key: number }>( + [ + { key: 1, a: 'a1' }, + { key: 6, a: 'a6' }, + { key: 5, a: 'a5' }, + { key: 3, a: 'a3' }, + { key: 2, a: 'a2' }, + { key: 4, a: 'a4' }, + { key: 0, a: 'a0' } + ], + { comparator: (a, b) => b.key - a.key } + ); + + const mappedMaxHeap = maxHeap.map( + item => item.key, + (a, b) => b - a + ); + expect(mappedMaxHeap.peek()).toBe(6); + expect(mappedMaxHeap.sort()).toEqual([6, 5, 4, 3, 2, 1, 0]); + + const mappedToElementFnMaxHeap = maxHeap.map< + string, + { + id: string; + } + >( + item => item.key.toString(), + (a, b) => Number(b) - Number(a), + rawElement => rawElement.id + ); + expect(mappedToElementFnMaxHeap.peek()).toBe('6'); + expect(mappedToElementFnMaxHeap.sort()).toEqual(['6', '5', '4', '3', '2', '1', '0']); + + const filteredHeap = maxHeap.filter(item => item.key > 3); + expect(filteredHeap.peek()).toEqual({ a: 'a6', key: 6 }); + expect(filteredHeap.sort()).toEqual([ + { a: 'a6', key: 6 }, + { a: 'a5', key: 5 }, + { a: 'a4', key: 4 } + ]); + }); }); diff --git a/test/unit/data-structures/heap/min-heap.test.ts b/test/unit/data-structures/heap/min-heap.test.ts index d64e286..b3c1aa8 100644 --- a/test/unit/data-structures/heap/min-heap.test.ts +++ b/test/unit/data-structures/heap/min-heap.test.ts @@ -5,7 +5,7 @@ describe('MinHeap', () => { let minHeap: MinHeap; beforeEach(() => { - minHeap = new MinHeap([], { comparator: numberComparator }); + minHeap = new MinHeap([], { comparator: numberComparator }); }); it('add and poll elements in ascending order', () => { @@ -40,6 +40,23 @@ describe('MinHeap', () => { expect(sortedArray).toEqual([1, 2, 3, 4]); }); + it('should clone', function () { + const minHeap = new MinHeap(); + minHeap.add('1'); + minHeap.add('6'); + minHeap.add('2'); + minHeap.add('0'); + minHeap.add('5'); + minHeap.add('9'); + minHeap.delete('2'); + expect([...minHeap]).toEqual(['0', '1', '9', '6', '5']); + const cloned = minHeap.clone(); + expect([...cloned]).toEqual(['0', '1', '9', '6', '5']); + minHeap.delete('5'); + expect([...minHeap]).toEqual(['0', '1', '9', '6']); + expect([...cloned]).toEqual(['0', '1', '9', '6', '5']); + }); + it('check if the heap is empty', () => { expect(minHeap.isEmpty()).toBe(true); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 5279846..fe8e718 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -50,6 +50,36 @@ describe('Deque - Basic Operations', () => { expect(deque.at(0)).toBe(3); }); + test('should at after shifting', () => { + deque.clear(); + for (let i = 0; i < 100; i++) { + deque.push(i); + } + + for (let i = 0; i < 10; i++) { + expect(deque.shift()).toBe(i); + } + + for (let i = 0; i < 90; i++) { + expect(deque.at(i)).toBe(i + 10); + } + }); + + test('should at after popping', () => { + deque.clear(); + for (let i = 0; i < 100; i++) { + deque.push(i); + } + + for (let i = 0; i < 10; i++) { + expect(deque.pop()).toBe(99 - i); + } + + for (let i = 0; i < 90; i++) { + expect(deque.at(i)).toBe(i); + } + }); + it('should clone', function () { const deque = new Deque(); deque.push('1'); diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 5d89eb5..b912d99 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -90,6 +90,62 @@ describe('Queue', () => { expect(queue.isEmpty()).toBeTruthy(); }); + test('should at after shifting', () => { + for (let i = 0; i < 100; i++) { + queue.push(i); + } + + for (let i = 0; i < 10; i++) { + expect(queue.shift()).toBe(i); + } + + for (let i = 0; i < 90; i++) { + expect(queue.at(i)).toBe(i + 10); + } + }); + + test('should toElementFn', () => { + const queue = new Queue([{ id: '1' }, { id: '5' }, { id: '3' }, { id: '4' }, { id: '2' }], { + toElementFn: rawElement => rawElement.id + }); + + expect(queue.size).toBe(5); + queue.shift(); + expect(queue.size).toBe(4); + expect(queue.at(1)).toBe('3'); + }); + + it('should object queue map & filter', function () { + const queue = new Queue<{ a: string; key: number }>([ + { key: 1, a: 'a1' }, + { key: 6, a: 'a6' }, + { key: 5, a: 'a5' }, + { key: 3, a: 'a3' }, + { key: 2, a: 'a2' }, + { key: 4, a: 'a4' }, + { key: 0, a: 'a0' } + ]); + + const mappedQueue = queue.map(item => item.key); + expect(mappedQueue.at(0)).toBe(1); + expect([...mappedQueue]).toEqual([1, 6, 5, 3, 2, 4, 0]); + + const mappedToElementFnQueue = queue.map( + item => item.key.toString(), + rawElement => rawElement.id + ); + expect(mappedToElementFnQueue.at(0)).toBe('1'); + expect([...mappedToElementFnQueue]).toEqual(['1', '6', '5', '3', '2', '4', '0']); + + const filteredQueue = queue.filter(item => item.key > 3); + expect(filteredQueue.at(0)).toEqual({ a: 'a6', key: 6 }); + expect([...filteredQueue]).toEqual([ + { a: 'a6', key: 6 }, + { a: 'a5', key: 5 }, + { a: 'a4', key: 4 } + ]); + }); + it('should clone', function () { const queue = new Queue(); queue.push('1');