UNPKG

doubly-linked-list-typed

Version:
553 lines (552 loc) 26.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LinearLinkedBase = exports.LinearBase = exports.LinkedListNode = void 0; const iterable_element_base_1 = require("./iterable-element-base"); class LinkedListNode { constructor(value) { this._value = value; this._next = undefined; } get value() { return this._value; } set value(value) { this._value = value; } get next() { return this._next; } set next(value) { this._next = value; } } exports.LinkedListNode = LinkedListNode; class LinearBase extends iterable_element_base_1.IterableElementBase { /** * The constructor initializes the LinearBase class with optional options, setting the maximum length * if provided. * @param [options] - The `options` parameter is an optional object that can be passed to the * constructor. It is of type `LinearBaseOptions<E, R>`. The constructor checks if the `options` * object is provided and then extracts the `maxLen` property from it. If `maxLen` is a */ constructor(options) { super(options); this._maxLen = -1; if (options) { const { maxLen } = options; if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen; } } get maxLen() { return this._maxLen; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The function indexOf searches for a specified element starting from a given index in an array-like * object and returns the index of the first occurrence, or -1 if not found. * @param {E} searchElement - The `searchElement` parameter in the `indexOf` function represents the * element that you want to find within the array. The function will search for this element starting * from the `fromIndex` (if provided) up to the end of the array. If the `searchElement` is found * within the * @param {number} [fromIndex=0] - The `fromIndex` parameter in the `indexOf` function represents the * index at which to start searching for the `searchElement` within the array. If provided, the * search will begin at this index and continue to the end of the array. If `fromIndex` is not * specified, the default * @returns The `indexOf` method is returning the index of the `searchElement` if it is found in the * array starting from the `fromIndex`. If the `searchElement` is not found, it returns -1. */ indexOf(searchElement, fromIndex = 0) { // Boundary checks and adjustments if (this.length === 0) return -1; if (fromIndex < 0) fromIndex = this.length + fromIndex; if (fromIndex < 0) fromIndex = 0; // Iterating from the specified index to the end for (let i = fromIndex; i < this.length; i++) { const element = this.at(i); if (element === searchElement) return i; } return -1; // Not found } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The function `lastIndexOf` in TypeScript returns the index of the last occurrence of a specified * element in an array. * @param {E} searchElement - The `searchElement` parameter is the element that you want to find the * last index of within the array. The `lastIndexOf` method will search the array starting from the * `fromIndex` (or the end of the array if not specified) and return the index of the last occurrence * of the * @param {number} fromIndex - The `fromIndex` parameter in the `lastIndexOf` method specifies the * index at which to start searching for the `searchElement` in the array. By default, it starts * searching from the last element of the array (`this.length - 1`). If a specific `fromIndex` is * provided * @returns The last index of the `searchElement` in the array is being returned. If the * `searchElement` is not found in the array, -1 is returned. */ lastIndexOf(searchElement, fromIndex = this.length - 1) { if (this.length === 0) return -1; if (fromIndex >= this.length) fromIndex = this.length - 1; if (fromIndex < 0) fromIndex = this.length + fromIndex; for (let i = fromIndex; i >= 0; i--) { const element = this.at(i); if (element === searchElement) return i; } return -1; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The `findIndex` function iterates over an array and returns the index of the first element that * satisfies the provided predicate function. * @param predicate - The `predicate` parameter in the `findIndex` function is a callback function * that takes three arguments: `item`, `index`, and the array `this`. It should return a boolean * value indicating whether the current element satisfies the condition being checked for. * @param {any} [thisArg] - The `thisArg` parameter in the `findIndex` function is an optional * parameter that specifies the value to use as `this` when executing the `predicate` function. If * provided, the `predicate` function will be called with `thisArg` as its `this` value. If ` * @returns The `findIndex` method is returning the index of the first element in the array that * satisfies the provided predicate function. If no such element is found, it returns -1. */ findIndex(predicate, thisArg) { for (let i = 0; i < this.length; i++) { const item = this.at(i); if (item !== undefined && predicate.call(thisArg, item, i, this)) return i; } return -1; } /** * Time Complexity: O(n + m) * Space Complexity: O(n + m) * * The `concat` function in TypeScript concatenates multiple items into a new list, handling both * individual elements and instances of `LinearBase`. * @param {(E | this)[]} items - The `concat` method takes in an array of items, where * each item can be either of type `E` or an instance of `LinearBase<E, R>`. * @returns The `concat` method is returning a new instance of the class that it belongs to, with the * items passed as arguments concatenated to it. */ concat(...items) { const newList = this.clone(); for (const item of items) { if (item instanceof LinearBase) { newList.pushMany(item); } else { newList.push(item); } } return newList; } /** * Time Complexity: O(n log n) * Space Complexity: O(n) * * The `sort` function in TypeScript sorts the elements of a collection using a specified comparison * function. * @param [compareFn] - The `compareFn` parameter is a function that defines the sort order. It takes * two elements `a` and `b` as input and returns a number indicating their relative order. If the * returned value is negative, `a` comes before `b`. If the returned value is positive, ` * @returns The `sort` method is returning the instance of the object on which it is called (this), * after sorting the elements based on the provided comparison function (compareFn). */ sort(compareFn) { const arr = this.toArray(); arr.sort(compareFn); this.clear(); for (const item of arr) this.push(item); return this; } /** * Time Complexity: O(n + m) * Space Complexity: O(m) * * The `splice` function in TypeScript removes elements from an array and optionally inserts new * elements at the specified index. * @param {number} start - The `start` parameter in the `splice` method indicates the index at which * to start modifying the array. If `start` is a negative number, it will count from the end of the * array. * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the * number of elements to remove from the array starting at the specified `start` index. If * `deleteCount` is not provided or is 0, no elements are removed, and only new elements are inserted * at the `start` * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that * will be inserted into the array at the specified `start` index. These elements can be of any type * and you can pass multiple elements separated by commas. The `splice` method will insert these * items into the array at the * @returns The `splice` method returns a list of elements that were removed from the original list * during the operation. */ splice(start, deleteCount = 0, ...items) { const removedList = this._createInstance(); // Handling negative indexes and bounds start = start < 0 ? this.length + start : start; start = Math.max(0, Math.min(start, this.length)); deleteCount = Math.max(0, Math.min(deleteCount, this.length - start)); // Delete elements for (let i = 0; i < deleteCount; i++) { const removed = this.deleteAt(start); // Always delete the start position if (removed !== undefined) { removedList.push(removed); // Add removed elements to the returned list } } // Insert new element for (let i = 0; i < items.length; i++) { this.addAt(start + i, items[i]); // Insert new elements one by one at the current position } return removedList; // Returns a list of removed elements } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The `join` function in TypeScript returns a string by joining the elements of an array with a * specified separator. * @param {string} [separator=,] - The `separator` parameter is a string that specifies the character * or characters that will be used to separate each element when joining them into a single string. * By default, the separator is set to a comma (`,`), but you can provide a different separator if * needed. * @returns The `join` method is being returned, which takes an optional `separator` parameter * (defaulting to a comma) and returns a string created by joining all elements of the array after * converting it to an array. */ join(separator = ',') { return this.toArray().join(separator); } /** * Time Complexity: O(n) * Space Complexity: O(n) * * The function `toReversedArray` takes an array and returns a new array with its elements in reverse * order. * @returns The `toReversedArray()` function returns an array of elements of type `E` in reverse * order. */ toReversedArray() { const array = []; for (let i = this.length - 1; i >= 0; i--) { array.push(this.at(i)); } return array; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The `reduceRight` function in TypeScript iterates over an array from right to left and applies a * callback function to each element, accumulating a single result. * @param callbackfn - The `callbackfn` parameter in the `reduceRight` method is a function that will * be called on each element in the array from right to left. It takes four arguments: * @param {U} [initialValue] - The `initialValue` parameter in the `reduceRight` method is an * optional parameter that specifies the initial value of the accumulator. If provided, the * `accumulator` will start with this initial value before iterating over the elements of the array. * If `initialValue` is not provided, the accumulator will * @returns The `reduceRight` method is returning the final accumulated value after applying the * callback function to each element in the array from right to left. */ reduceRight(callbackfn, initialValue) { let accumulator = initialValue !== null && initialValue !== void 0 ? initialValue : 0; for (let i = this.length - 1; i >= 0; i--) { accumulator = callbackfn(accumulator, this.at(i), i, this); } return accumulator; } /** * Time Complexity: O(m) * Space Complexity: O(m) * * The `slice` function in TypeScript creates a new instance by extracting a portion of elements from * the original instance based on the specified start and end indices. * @param {number} [start=0] - The `start` parameter in the `slice` method represents the index at * which to begin extracting elements from an array-like object. If no `start` parameter is provided, * the default value is 0, meaning the extraction will start from the beginning of the array. * @param {number} end - The `end` parameter in the `slice` method represents the index at which to * end the slicing. By default, if no `end` parameter is provided, it will slice until the end of the * array (i.e., `this.length`). * @returns The `slice` method is returning a new instance of the object with elements sliced from * the specified start index (default is 0) to the specified end index (default is the length of the * object). */ slice(start = 0, end = this.length) { start = start < 0 ? this.length + start : start; end = end < 0 ? this.length + end : end; const newList = this._createInstance(); for (let i = start; i < end; i++) { newList.push(this.at(i)); } return newList; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The `fill` function in TypeScript fills a specified range in an array-like object with a given * value. * @param {E} value - The `value` parameter in the `fill` method represents the element that will be * used to fill the specified range in the array. * @param [start=0] - The `start` parameter specifies the index at which to start filling the array * with the specified value. If not provided, it defaults to 0, indicating the beginning of the * array. * @param end - The `end` parameter in the `fill` function represents the index at which the filling * of values should stop. It specifies the end of the range within the array where the `value` should * be filled. * @returns The `fill` method is returning the modified object (`this`) after filling the specified * range with the provided value. */ fill(value, start = 0, end = this.length) { // Handling negative indexes start = start < 0 ? this.length + start : start; end = end < 0 ? this.length + end : end; // Boundary processing if (start < 0) start = 0; if (end > this.length) end = this.length; if (start >= end) return this; // Iterate through the specified range and fill in the values for (let i = start; i < end; i++) { this.setAt(i, value); } return this; } } exports.LinearBase = LinearBase; class LinearLinkedBase extends LinearBase { /** * The constructor initializes the LinearBase class with optional options, setting the maximum length * if provided and valid. * @param [options] - The `options` parameter is an optional object that can be passed to the * constructor. It is of type `LinearBaseOptions<E, R>`. This object may contain properties such as * `maxLen`, which is a number representing the maximum length. If `maxLen` is a positive integer, */ constructor(options) { super(options); if (options) { const { maxLen } = options; if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen; } } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The function overrides the indexOf method to improve performance by searching for an element in a * custom array implementation starting from a specified index. * @param {E} searchElement - The `searchElement` parameter is the element that you are searching for * within the array. The `indexOf` method will return the index of the first occurrence of this * element within the array. * @param {number} [fromIndex=0] - The `fromIndex` parameter in the `indexOf` method specifies the * index in the array at which to start the search for the `searchElement`. If provided, the search * will begin at the specified index and continue to the end of the array. If not provided, the * search will start at index * @returns The `indexOf` method is returning the index of the `searchElement` if it is found in the * array starting from the `fromIndex`. If the `searchElement` is not found, it returns -1. */ indexOf(searchElement, fromIndex = 0) { // In order to improve performance, it is best to override this method in the subclass of the array implementation const iterator = this._getIterator(); let current = iterator.next(); let index = 0; while (index < fromIndex) { current = iterator.next(); index++; } while (!current.done) { if (current.value === searchElement) return index; current = iterator.next(); index++; } return -1; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The function overrides the lastIndexOf method in TypeScript to improve performance by searching * for an element in reverse order starting from a specified index. * @param {E} searchElement - The `searchElement` parameter is the element that you want to find * within the array. The `lastIndexOf` method searches the array for this element starting from the * end of the array (or from the specified `fromIndex` if provided) and returns the index of the last * occurrence of the element * @param {number} fromIndex - The `fromIndex` parameter in the `lastIndexOf` method specifies the * index at which to start searching for the `searchElement` in the array. If provided, the search * will begin at this index and move towards the beginning of the array. If not provided, the search * will start at the * @returns The `lastIndexOf` method is being overridden to search for the `searchElement` starting * from the specified `fromIndex` (defaulting to the end of the array). It iterates over the array in * reverse order using a custom iterator `_getReverseIterator` and returns the index of the last * occurrence of the `searchElement` if found, or -1 if not found. */ lastIndexOf(searchElement, fromIndex = this.length - 1) { // In order to improve performance, it is best to override this method in the subclass of the array implementation const iterator = this._getReverseIterator(); let current = iterator.next(); let index = this.length - 1; while (index > fromIndex) { current = iterator.next(); index--; } while (!current.done) { if (current.value === searchElement) return index; current = iterator.next(); index--; } return -1; } /** * Time Complexity: O(n + m) * Space Complexity: O(n + m) * * The `concat` function in TypeScript overrides the default behavior to concatenate items into a new * list, handling both individual elements and instances of `LinearBase`. * @param {(E | LinearBase<E, R>)[]} items - The `concat` method you provided takes in a variable * number of arguments of type `E` or `LinearBase<E, R>`. The method concatenates these items to the * current list and returns a new list with the concatenated items. * @returns The `concat` method is returning a new instance of the class that it belongs to, with the * items passed as arguments concatenated to it. */ concat(...items) { const newList = this.clone(); for (const item of items) { if (item instanceof LinearBase) { newList.pushMany(item); } else { newList.push(item); } } return newList; } /** * Time Complexity: O(m) * Space Complexity: O(m) * * The `slice` method is overridden to improve performance by creating a new instance and iterating * through the array to extract a subset based on the specified start and end indices. * @param {number} [start=0] - The `start` parameter in the `slice` method specifies the index at * which to begin extracting elements from the array. If no `start` parameter is provided, the * default value is 0, indicating that extraction should start from the beginning of the array. * @param {number} end - The `end` parameter in the `slice` method represents the index at which to * end the slicing of the array. If not provided, it defaults to the length of the array. * @returns The `slice` method is returning a new instance of the array implementation with elements * sliced from the original array based on the `start` and `end` parameters. */ slice(start = 0, end = this.length) { // In order to improve performance, it is best to override this method in the subclass of the array implementation start = start < 0 ? this.length + start : start; end = end < 0 ? this.length + end : end; const newList = this._createInstance(); const iterator = this._getIterator(); let current = iterator.next(); let c = 0; while (c < start) { current = iterator.next(); c++; } for (let i = start; i < end; i++) { newList.push(current.value); current = iterator.next(); } return newList; } /** * Time Complexity: O(n + m) * Space Complexity: O(m) * * The function overrides the splice method to handle deletion and insertion of elements in a data * structure while returning the removed elements. * @param {number} start - The `start` parameter in the `splice` method indicates the index at which * to start modifying the array. * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the * number of elements to remove from the array starting at the specified `start` index. If * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new * elements can still be inserted at * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that * will be inserted into the array at the specified `start` index. These elements can be of any type * and there can be multiple elements passed as arguments to be inserted into the array. * @returns The `splice` method is returning a new instance of the data structure that was modified * by removing elements specified by the `start` and `deleteCount` parameters, and inserting new * elements provided in the `items` array. */ splice(start, deleteCount = 0, ...items) { const removedList = this._createInstance(); // Used to store deleted elements // Handling negative indexes start = start < 0 ? this.length + start : start; start = Math.max(0, Math.min(start, this.length)); // Correct start range deleteCount = Math.max(0, deleteCount); // Make sure deleteCount is non-negative let currentIndex = 0; let currentNode = undefined; let previousNode = undefined; // Find the starting point using an iterator const iterator = this._getNodeIterator(); for (const node of iterator) { if (currentIndex === start) { currentNode = node; // Find the starting node break; } previousNode = node; // Update the previous node currentIndex++; } // Delete nodes for (let i = 0; i < deleteCount && currentNode; i++) { removedList.push(currentNode.value); // Store the deleted value in removedList const nextNode = currentNode.next; // Save next node this.delete(currentNode); // Delete current node currentNode = nextNode; } // Insert new value for (let i = 0; i < items.length; i++) { if (previousNode) { this.addAfter(previousNode, items[i]); // Insert after previousNode previousNode = previousNode.next; // Move to newly inserted node } else { this.addAt(0, items[i]); // Insert at the head of the linked list previousNode = this._getNodeIterator().next().value; // Update the head node to be the first inserted node } } return removedList; } /** * Time Complexity: O(n) * Space Complexity: O(1) * * The function `reduceRight` iterates over an array in reverse order and applies a callback function * to each element, accumulating a single result. * @param callbackfn - The `callbackfn` parameter is a function that will be called on each element * of the array from right to left. It takes four arguments: * @param {U} [initialValue] - The `initialValue` parameter is an optional value that is used as the * initial accumulator value in the reduce operation. If provided, the reduce operation starts with * this initial value and iterates over the elements of the array, applying the callback function to * each element and the current accumulator value. If `initial * @returns The `reduceRight` method is returning the final accumulated value after applying the * callback function to each element in the array from right to left. */ reduceRight(callbackfn, initialValue) { let accumulator = initialValue !== null && initialValue !== void 0 ? initialValue : 0; let index = this.length - 1; for (const item of this._getReverseIterator()) { accumulator = callbackfn(accumulator, item, index--, this); } return accumulator; } } exports.LinearLinkedBase = LinearLinkedBase;