doubly-linked-list-typed
Version:
Doubly Linked List
459 lines (458 loc) • 22.1 kB
TypeScript
/**
* data-structure-typed
*
* @author Pablo Zeng
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { DequeOptions, ElementCallback, IterableWithSizeOrLength } from '../../types';
import { LinearBase } from '../base/linear-base';
/**
* 1. Operations at Both Ends: Supports adding and removing elements at both the front and back of the queue. This allows it to be used as a stack (last in, first out) and a queue (first in, first out).
* 2. Efficient Random Access: Being based on an array, it offers fast random access capability, allowing constant time access to any element.
* 3. Continuous Memory Allocation: Since it is based on an array, all elements are stored contiguously in memory, which can bring cache friendliness and efficient memory access.
* 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
* @example
* // prize roulette
* class PrizeRoulette {
* private deque: Deque<string>;
*
* constructor(prizes: string[]) {
* // Initialize the deque with prizes
* this.deque = new Deque<string>(prizes);
* }
*
* // Rotate clockwise to the right (forward)
* rotateClockwise(steps: number): void {
* const n = this.deque.length;
* if (n === 0) return;
*
* for (let i = 0; i < steps; i++) {
* const last = this.deque.pop(); // Remove the last element
* this.deque.unshift(last!); // Add it to the front
* }
* }
*
* // Rotate counterclockwise to the left (backward)
* rotateCounterClockwise(steps: number): void {
* const n = this.deque.length;
* if (n === 0) return;
*
* for (let i = 0; i < steps; i++) {
* const first = this.deque.shift(); // Remove the first element
* this.deque.push(first!); // Add it to the back
* }
* }
*
* // Display the current prize at the head
* display() {
* return this.deque.first;
* }
* }
*
* // Example usage
* const prizes = ['Car', 'Bike', 'Laptop', 'Phone', 'Watch', 'Headphones']; // Initialize the prize list
* const roulette = new PrizeRoulette(prizes);
*
* // Display the initial state
* console.log(roulette.display()); // 'Car' // Car
*
* // Rotate clockwise by 3 steps
* roulette.rotateClockwise(3);
* console.log(roulette.display()); // 'Phone' // Phone
*
* // Rotate counterclockwise by 2 steps
* roulette.rotateCounterClockwise(2);
* console.log(roulette.display()); // 'Headphones'
* @example
* // sliding window
* // Maximum function of sliding window
* function maxSlidingWindow(nums: number[], k: number): number[] {
* const n = nums.length;
* if (n * k === 0) return [];
*
* const deq = new Deque<number>();
* const result: number[] = [];
*
* for (let i = 0; i < n; i++) {
* // Delete indexes in the queue that are not within the window range
* if (deq.length > 0 && deq.first! === i - k) {
* deq.shift();
* }
*
* // Remove all indices less than the current value from the tail of the queue
* while (deq.length > 0 && nums[deq.last!] < nums[i]) {
* deq.pop();
* }
*
* // Add the current index to the end of the queue
* deq.push(i);
*
* // Add the maximum value of the window to the results
* if (i >= k - 1) {
* result.push(nums[deq.first!]);
* }
* }
*
* return result;
* }
*
* const nums = [1, 3, -1, -3, 5, 3, 6, 7];
* const k = 3;
* console.log(maxSlidingWindow(nums, k)); // [3, 3, 5, 5, 6, 7]
*/
export declare class Deque<E = any, R = any> extends LinearBase<E, R> {
/**
* 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
* empty deque
* @param {DequeOptions} [options] - The `options` parameter is an optional object that can contain
* configuration options for the deque. In this code, it is used to set the `bucketSize` option,
* 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<E> | IterableWithSizeOrLength<R>, options?: DequeOptions<E, R>);
protected _bucketSize: number;
get bucketSize(): number;
protected _bucketFirst: number;
get bucketFirst(): number;
protected _firstInBucket: number;
get firstInBucket(): number;
protected _bucketLast: number;
get bucketLast(): number;
protected _lastInBucket: number;
get lastInBucket(): number;
protected _bucketCount: number;
get bucketCount(): number;
protected _buckets: E[][];
get buckets(): E[][];
protected _length: number;
get length(): number;
/**
* The function returns the first element in a collection if it exists, otherwise it returns
* undefined.
* @returns The first element of the collection, of type E, is being returned.
*/
get first(): E | undefined;
/**
* The last function returns the last element in the queue.
* @return The last element in the array
*/
get last(): E | undefined;
/**
* Time Complexity - Amortized O(1) (possible reallocation),
* Space Complexity - O(n) (due to potential resizing).
*
* The push function adds an element to a data structure and reallocates memory if necessary.
* @param {E} element - The `element` parameter represents the value that you want to add to the data
* structure.
* @returns The size of the data structure after the element has been pushed.
*/
push(element: E): boolean;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `pop()` function removes and returns the last element from a data structure, updating the
* internal state variables accordingly.
* @returns The element that was removed from the data structure is being returned.
*/
pop(): E | undefined;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `shift()` function removes and returns the first element from a data structure, updating the
* internal state variables accordingly.
* @returns The element that is being removed from the beginning of the data structure is being
* returned.
*/
shift(): E | undefined;
/**
* Time Complexity: Amortized O(1)
* Space Complexity: O(n)
*
* The `unshift` function adds an element to the beginning of an array-like data structure and
* returns the new size of the structure.
* @param {E} element - The `element` parameter represents the element that you want to add to the
* beginning of the data structure.
* @returns The size of the data structure after the element has been added.
*/
unshift(element: E): boolean;
/**
* Time Complexity: O(k)
* Space Complexity: O(k)
*
* The function `pushMany` iterates over elements and pushes them into an array after applying a
* transformation function if provided.
* @param {IterableWithSizeOrLength<E> | IterableWithSizeOrLength<R>} elements - The `elements`
* parameter in the `pushMany` function is expected to be an iterable containing elements of type `E`
* or `R`. It can be either an `IterableWithSizeOrLength<E>` or an `IterableWithSizeOrLength<R>`. The
* function iterates over each element
* @returns The `pushMany` function is returning an array of boolean values, where each value
* represents the result of calling the `push` method on the current object instance with the
* corresponding element from the input `elements` iterable.
*/
pushMany(elements: IterableWithSizeOrLength<E> | IterableWithSizeOrLength<R>): boolean[];
/**
* Time Complexity: O(k)
* Space Complexity: O(k)
*
* The `unshiftMany` function in TypeScript iterates over elements and adds them to the beginning of
* an array, optionally converting them using a provided function.
* @param {IterableWithSizeOrLength<E> | IterableWithSizeOrLength<R>} elements - The `elements`
* parameter in the `unshiftMany` function is an iterable containing elements of type `E` or `R`. It
* can be an array or any other iterable data structure that has a known size or length. The function
* iterates over each element in the `elements` iterable and
* @returns The `unshiftMany` function returns an array of boolean values indicating whether each
* element was successfully added to the beginning of the array.
*/
unshiftMany(elements?: IterableWithSizeOrLength<E> | IterableWithSizeOrLength<R>): boolean[];
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function checks if the size of an object is equal to zero and returns a boolean value.
* @returns A boolean value indicating whether the size of the object is 0 or not.
*/
isEmpty(): boolean;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The clear() function resets the state of the object by initializing all variables to their default
* values.
*/
clear(): void;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `at` function retrieves an element at a specified position in an array-like data structure.
* @param {number} pos - The `pos` parameter represents the position of the element that you want to
* retrieve from the data structure. It is of type `number` and should be a valid index within the
* range of the data structure.
* @returns The element at the specified position in the data structure is being returned.
*/
at(pos: number): E;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `setAt` function sets an element at a specific position in an array-like data structure.
* @param {number} pos - The `pos` parameter represents the position at which the element needs to be
* set. It is of type `number`.
* @param {E} element - The `element` parameter is the value that you want to set at the specified
* position in the data structure.
*/
setAt(pos: number, element: E): boolean;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `addAt` function inserts one or more elements at a specified position in an array-like data
* structure.
* @param {number} pos - The `pos` parameter represents the position at which the element(s) should
* be inserted. It is of type `number`.
* @param {E} element - The `element` parameter represents the element that you want to insert into
* the array at the specified position.
* @param [num=1] - The `num` parameter represents the number of times the `element` should be
* inserted at the specified position (`pos`). By default, it is set to 1, meaning that the `element`
* will be inserted once. However, you can provide a different value for `num` if you want
* @returns The size of the array after the insertion is being returned.
*/
addAt(pos: number, element: E, num?: number): boolean;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The `cut` function updates the state of the object based on the given position and returns the
* updated size.
* @param {number} pos - The `pos` parameter represents the position at which the string should be
* cut. It is a number that indicates the index of the character where the cut should be made.
* @param {boolean} isCutSelf - If true, the original deque will not be cut, and return a new deque
* @returns The method is returning the updated size of the data structure.
*/
cut(pos: number, isCutSelf?: boolean): Deque<E>;
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The `splice` function in TypeScript overrides the default behavior to remove and insert elements
* in a Deque data structure while ensuring the starting position and delete count are within bounds.
* @param {number} start - The `start` parameter in the `splice` method represents the index at which
* to start changing the array. Items will be removed or added starting from this index.
* @param {number} deleteCount - The `deleteCount` parameter in the `splice` method represents the
* number of elements to remove from the array starting at the specified `start` index. If
* `deleteCount` is not provided, it defaults to the number of elements from the `start` index to the
* end of the array (`
* @param {E[]} items - The `items` parameter in the `splice` method represents the elements that
* will be inserted into the deque at the specified `start` index. These elements will be inserted in
* place of the elements that are removed based on the `start` and `deleteCount` parameters.
* @returns The `splice` method is returning the array `deletedElements` which contains the elements
* that were removed from the Deque during the splice operation.
*/
splice(start: number, deleteCount?: number, ...items: E[]): this;
/**
* Time Complexity: O(1)
* Space Complexity: O(1) or O(n)
*
* The `cutRest` function cuts the elements from a specified position in a deque and returns a new
* deque with the cut elements.
* @param {number} pos - The `pos` parameter represents the position from which to cut the Deque. It
* is a number that indicates the index of the element in the Deque where the cut should start.
* @param [isCutSelf=false] - isCutSelf is a boolean parameter that determines whether the original
* Deque should be modified or a new Deque should be created. If isCutSelf is true, the original
* Deque will be modified by cutting off elements starting from the specified position. If isCutSelf
* is false, a new De
* @returns The function `cutRest` returns either the modified original deque (`this`) or a new deque
* (`newDeque`) depending on the value of the `isCutSelf` parameter.
*/
cutRest(pos: number, isCutSelf?: boolean): Deque<E>;
/**
* Time Complexity: O(n)
* Space Complexity: O(1) or O(n)
*
* The `deleteAt` function removes an element at a specified position in an array-like data
* structure.
* @param {number} pos - The `pos` parameter in the `deleteAt` function represents the position at
* which an element needs to be deleted from the data structure. It is of type `number` and indicates
* the index of the element to be deleted.
* @returns The size of the data structure after the deletion operation is performed.
*/
deleteAt(pos: number): E | undefined;
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The `delete` function removes all occurrences of a specified element from an array-like data
* structure.
* @param {E} element - The `element` parameter represents the element that you want to delete from
* the data structure.
* @returns The size of the data structure after the element has been deleted.
*/
delete(element: E): boolean;
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The reverse() function reverses the order of the buckets and the elements within each bucket in a
* data structure.
* @returns The reverse() method is returning the object itself (this) after performing the reverse
* operation on the buckets and updating the relevant properties.
*/
reverse(): this;
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The `unique()` function removes duplicate elements from an array-like data structure and returns
* the number of unique elements.
* @returns The size of the modified array is being returned.
*/
unique(): this;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `shrinkToFit` function reorganizes the elements in an array-like data structure to minimize
* memory usage.
* @returns Nothing is being returned. The function is using the `return` statement to exit early if
* `this._length` is 0, but it does not return any value.
*/
shrinkToFit(): void;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `clone()` function returns a new instance of the `Deque` class with the same elements and
* bucket size as the original instance.
* @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(): this;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `filter` function creates a new deque containing elements from the original deque that satisfy
* a given predicate function.
* @param predicate - The `predicate` parameter is a callback function that takes three arguments:
* the current element being iterated over, the index of the current element, and the deque itself.
* It should return a boolean value indicating whether the element should be included in the filtered
* deque 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 `filter` method is returning a new `Deque` object that contains the elements that
* satisfy the given predicate function.
*/
filter(predicate: ElementCallback<E, R, boolean>, thisArg?: any): Deque<E, R>;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `map` function takes a callback function and applies it to each element in the deque,
* returning a new deque with the results.
* @param callback - The callback parameter is a function that 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<EM, RM>(callback: ElementCallback<E, R, EM>, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Deque<EM, RM>;
/**
* Time Complexity: O(n)
* Space Complexity: O(1)
*
* The above function is an implementation of the iterator protocol in TypeScript, allowing the
* object to be iterated over using a for...of loop.
*/
protected _getIterator(): IterableIterator<E>;
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The `_reallocate` function reallocates the buckets in an array, adding new buckets if needed.
* @param {number} [needBucketNum] - The `needBucketNum` parameter is an optional number that
* specifies the number of new buckets needed. If not provided, it will default to half of the
* current bucket count (`this._bucketCount >> 1`) or 1 if the current bucket count is less than 2.
*/
protected _reallocate(needBucketNum?: number): void;
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function calculates the bucket index and index within the bucket based on the given position.
* @param {number} pos - The `pos` parameter represents the position within the data structure. It is
* a number that indicates the index or position of an element within the structure.
* @returns an object with two properties: "bucketIndex" and "indexInBucket".
*/
protected _getBucketAndPosition(pos: number): {
bucketIndex: number;
indexInBucket: number;
};
/**
* The function `_createInstance` returns a new instance of the `Deque` class with the specified
* options.
* @param [options] - The `options` parameter in the `_createInstance` method is of type
* `DequeOptions<E, R>`, which is an optional parameter that allows you to pass additional
* configuration options when creating a new instance of the `Deque` class.
* @returns An instance of the `Deque` class with an empty array and the provided options, casted as
* `this`.
*/
protected _createInstance(options?: DequeOptions<E, R>): this;
/**
* This function returns an iterator that iterates over elements in reverse order.
*/
protected _getReverseIterator(): IterableIterator<E>;
}