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