bst-typed 1.54.3 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/data-structures/base/iterable-element-base.d.ts +14 -40
  2. package/dist/data-structures/base/iterable-element-base.js +14 -11
  3. package/dist/data-structures/base/linear-base.d.ts +277 -0
  4. package/dist/data-structures/base/linear-base.js +552 -0
  5. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +12 -8
  6. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +50 -37
  7. package/dist/data-structures/binary-tree/avl-tree.d.ts +64 -0
  8. package/dist/data-structures/binary-tree/avl-tree.js +64 -0
  9. package/dist/data-structures/binary-tree/binary-tree.js +5 -5
  10. package/dist/data-structures/binary-tree/bst.js +11 -11
  11. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +175 -14
  12. package/dist/data-structures/binary-tree/tree-multi-map.js +210 -40
  13. package/dist/data-structures/graph/abstract-graph.js +16 -16
  14. package/dist/data-structures/hash/hash-map.d.ts +46 -0
  15. package/dist/data-structures/hash/hash-map.js +46 -0
  16. package/dist/data-structures/heap/heap.d.ts +3 -11
  17. package/dist/data-structures/heap/heap.js +0 -10
  18. package/dist/data-structures/heap/max-heap.d.ts +2 -2
  19. package/dist/data-structures/heap/min-heap.d.ts +2 -2
  20. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +65 -94
  21. package/dist/data-structures/linked-list/doubly-linked-list.js +131 -146
  22. package/dist/data-structures/linked-list/singly-linked-list.d.ts +145 -75
  23. package/dist/data-structures/linked-list/singly-linked-list.js +283 -169
  24. package/dist/data-structures/priority-queue/max-priority-queue.d.ts +2 -2
  25. package/dist/data-structures/priority-queue/min-priority-queue.d.ts +2 -2
  26. package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -2
  27. package/dist/data-structures/queue/deque.d.ts +130 -91
  28. package/dist/data-structures/queue/deque.js +269 -169
  29. package/dist/data-structures/queue/queue.d.ts +131 -40
  30. package/dist/data-structures/queue/queue.js +181 -50
  31. package/dist/data-structures/stack/stack.d.ts +124 -11
  32. package/dist/data-structures/stack/stack.js +121 -10
  33. package/dist/data-structures/trie/trie.d.ts +4 -3
  34. package/dist/data-structures/trie/trie.js +3 -0
  35. package/dist/types/data-structures/base/base.d.ts +9 -4
  36. package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +1 -1
  37. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1 -1
  38. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +2 -2
  39. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +2 -2
  40. package/dist/types/data-structures/queue/deque.d.ts +2 -3
  41. package/dist/types/data-structures/queue/queue.d.ts +2 -2
  42. package/package.json +2 -2
  43. package/src/data-structures/base/iterable-element-base.ts +29 -20
  44. package/src/data-structures/base/linear-base.ts +649 -0
  45. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +51 -36
  46. package/src/data-structures/binary-tree/avl-tree.ts +64 -0
  47. package/src/data-structures/binary-tree/binary-tree.ts +5 -5
  48. package/src/data-structures/binary-tree/bst.ts +9 -9
  49. package/src/data-structures/binary-tree/tree-multi-map.ts +214 -40
  50. package/src/data-structures/graph/abstract-graph.ts +16 -16
  51. package/src/data-structures/hash/hash-map.ts +46 -0
  52. package/src/data-structures/heap/heap.ts +3 -14
  53. package/src/data-structures/heap/max-heap.ts +2 -2
  54. package/src/data-structures/heap/min-heap.ts +2 -2
  55. package/src/data-structures/linked-list/doubly-linked-list.ts +144 -160
  56. package/src/data-structures/linked-list/singly-linked-list.ts +307 -185
  57. package/src/data-structures/priority-queue/max-priority-queue.ts +2 -5
  58. package/src/data-structures/priority-queue/min-priority-queue.ts +2 -5
  59. package/src/data-structures/priority-queue/priority-queue.ts +2 -2
  60. package/src/data-structures/queue/deque.ts +286 -183
  61. package/src/data-structures/queue/queue.ts +196 -63
  62. package/src/data-structures/stack/stack.ts +124 -18
  63. package/src/data-structures/trie/trie.ts +7 -3
  64. package/src/types/data-structures/base/base.ts +17 -8
  65. package/src/types/data-structures/binary-tree/avl-tree-multi-map.ts +1 -1
  66. package/src/types/data-structures/binary-tree/tree-multi-map.ts +1 -1
  67. package/src/types/data-structures/linked-list/doubly-linked-list.ts +2 -2
  68. package/src/types/data-structures/linked-list/singly-linked-list.ts +2 -2
  69. package/src/types/data-structures/queue/deque.ts +2 -3
  70. package/src/types/data-structures/queue/queue.ts +2 -2
@@ -4,8 +4,8 @@
4
4
  * @class
5
5
  */
6
6
  import type { ElementCallback, QueueOptions } from '../../types';
7
- import { IterableElementBase } from '../base';
8
7
  import { SinglyLinkedList } from '../linked-list';
8
+ import { LinearBase } from '../base/linear-base';
9
9
 
10
10
  /**
11
11
  * 1. First In, First Out (FIFO): The core feature of a queue is its first in, first out nature. The element added to the queue first will be the one to be removed first.
@@ -15,8 +15,55 @@ import { SinglyLinkedList } from '../linked-list';
15
15
  * 5. Data Buffering: Acting as a buffer for data packets in network communication.
16
16
  * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
17
17
  * 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
18
+ * @example
19
+ * // Sliding Window using Queue
20
+ * const nums = [2, 3, 4, 1, 5];
21
+ * const k = 2;
22
+ * const queue = new Queue<number>();
23
+ *
24
+ * let maxSum = 0;
25
+ * let currentSum = 0;
26
+ *
27
+ * nums.forEach((num, i) => {
28
+ * queue.push(num);
29
+ * currentSum += num;
30
+ *
31
+ * if (queue.length > k) {
32
+ * currentSum -= queue.shift()!;
33
+ * }
34
+ *
35
+ * if (queue.length === k) {
36
+ * maxSum = Math.max(maxSum, currentSum);
37
+ * }
38
+ * });
39
+ *
40
+ * console.log(maxSum); // 7
41
+ * @example
42
+ * // Breadth-First Search (BFS) using Queue
43
+ * const graph: { [key in number]: number[] } = {
44
+ * 1: [2, 3],
45
+ * 2: [4, 5],
46
+ * 3: [],
47
+ * 4: [],
48
+ * 5: []
49
+ * };
50
+ *
51
+ * const queue = new Queue<number>();
52
+ * const visited: number[] = [];
53
+ *
54
+ * queue.push(1);
55
+ *
56
+ * while (!queue.isEmpty()) {
57
+ * const node = queue.shift()!;
58
+ * if (!visited.includes(node)) {
59
+ * visited.push(node);
60
+ * graph[node].forEach(neighbor => queue.push(neighbor));
61
+ * }
62
+ * }
63
+ *
64
+ * console.log(visited); // [1, 2, 3, 4, 5]
18
65
  */
19
- export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E, R>> {
66
+ export class Queue<E = any, R = any> extends LinearBase<E, R> {
20
67
  constructor(elements: Iterable<E> | Iterable<R> = [], options?: QueueOptions<E, R>) {
21
68
  super(options);
22
69
 
@@ -30,42 +77,40 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
30
77
 
31
78
  protected _elements: E[] = [];
32
79
 
33
- /**
34
- * The elements function returns the elements of this set.
35
- * @return An array of the elements in the stack
36
- */
37
80
  get elements(): E[] {
38
81
  return this._elements;
39
82
  }
40
83
 
41
84
  protected _offset: number = 0;
42
85
 
43
- /**
44
- * The offset function returns the offset of the current page.
45
- * @return The value of the protected variable _offset
46
- */
47
86
  get offset(): number {
48
87
  return this._offset;
49
88
  }
50
89
 
51
- /**
52
- * The size function returns the number of elements in an array.
53
- * @returns {number} The size of the array, which is the difference between the length of the array and the offset.
54
- */
55
- get size(): number {
90
+ get length(): number {
56
91
  return this.elements.length - this.offset;
57
92
  }
58
93
 
94
+ protected _autoCompactRatio: number = 0.5;
95
+
96
+ get autoCompactRatio(): number {
97
+ return this._autoCompactRatio;
98
+ }
99
+
100
+ set autoCompactRatio(v: number) {
101
+ this._autoCompactRatio = v;
102
+ }
103
+
59
104
  /**
60
105
  * Time Complexity: O(1)
61
106
  * Space Complexity: O(1)
62
107
  *
63
108
  * The `first` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
64
109
  * @returns The `get first()` method returns the first element of the data structure, represented by the `_elements` array at
65
- * the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
110
+ * the `_offset` index. If the data structure is empty (length is 0), it returns `undefined`.
66
111
  */
67
112
  get first(): E | undefined {
68
- return this.size > 0 ? this.elements[this.offset] : undefined;
113
+ return this.length > 0 ? this.elements[this.offset] : undefined;
69
114
  }
70
115
 
71
116
  /**
@@ -77,26 +122,7 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
77
122
  * array is empty, it returns `undefined`.
78
123
  */
79
124
  get last(): E | undefined {
80
- return this.size > 0 ? this.elements[this.elements.length - 1] : undefined;
81
- }
82
-
83
- protected _autoCompactRatio: number = 0.5;
84
-
85
- /**
86
- * This function returns the value of the autoCompactRatio property.
87
- * @returns The `autoCompactRatio` property of the object, which is a number.
88
- */
89
- get autoCompactRatio(): number {
90
- return this._autoCompactRatio;
91
- }
92
-
93
- /**
94
- * The above function sets the autoCompactRatio property to a specified number in TypeScript.
95
- * @param {number} v - The parameter `v` represents the value that will be assigned to the
96
- * `_autoCompactRatio` property.
97
- */
98
- set autoCompactRatio(v: number) {
99
- this._autoCompactRatio = v;
125
+ return this.length > 0 ? this.elements[this.elements.length - 1] : undefined;
100
126
  }
101
127
 
102
128
  /**
@@ -123,6 +149,7 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
123
149
  */
124
150
  push(element: E): boolean {
125
151
  this.elements.push(element);
152
+ if (this._maxLen > 0 && this.length > this._maxLen) this.shift();
126
153
  return true;
127
154
  }
128
155
 
@@ -155,7 +182,7 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
155
182
  * @returns The function `shift()` returns either the first element in the queue or `undefined` if the queue is empty.
156
183
  */
157
184
  shift(): E | undefined {
158
- if (this.size === 0) return undefined;
185
+ if (this.length === 0) return undefined;
159
186
 
160
187
  const first = this.first;
161
188
  this._offset += 1;
@@ -174,7 +201,7 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
174
201
  */
175
202
  delete(element: E): boolean {
176
203
  const index = this.elements.indexOf(element);
177
- return this.deleteAt(index);
204
+ return !!this.deleteAt(index);
178
205
  }
179
206
 
180
207
  /**
@@ -185,9 +212,10 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
185
212
  * @param {number} index - Determine the index of the element to be deleted
186
213
  * @return A boolean value
187
214
  */
188
- deleteAt(index: number): boolean {
189
- const spliced = this.elements.splice(index, 1);
190
- return spliced.length === 1;
215
+ deleteAt(index: number): E | undefined {
216
+ const deleted = this.elements[index];
217
+ this.elements.splice(index, 1);
218
+ return deleted;
191
219
  }
192
220
 
193
221
  /**
@@ -205,26 +233,69 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
205
233
  return this.elements[index + this._offset];
206
234
  }
207
235
 
236
+ /**
237
+ * Time Complexity: O(n)
238
+ * Space Complexity: O(1)
239
+ *
240
+ * The `reverse` function in TypeScript reverses the elements of an array starting from a specified
241
+ * offset.
242
+ * @returns The `reverse()` method is returning the modified object itself (`this`) after reversing
243
+ * the elements in the array and resetting the offset to 0.
244
+ */
245
+ reverse(): this {
246
+ this._elements = this.elements.slice(this.offset).reverse();
247
+ this._offset = 0;
248
+ return this;
249
+ }
250
+
251
+ /**
252
+ * Time Complexity: O(n)
253
+ * Space Complexity: O(1)
254
+ *
255
+ * The function `addAt` inserts a new element at a specified index in an array, returning true if
256
+ * successful and false if the index is out of bounds.
257
+ * @param {number} index - The `index` parameter represents the position at which the `newElement`
258
+ * should be added in the array.
259
+ * @param {E} newElement - The `newElement` parameter represents the element that you want to insert
260
+ * into the array at the specified index.
261
+ * @returns The `addAt` method returns a boolean value - `true` if the new element was successfully
262
+ * added at the specified index, and `false` if the index is out of bounds (less than 0 or greater
263
+ * than the length of the array).
264
+ */
265
+ addAt(index: number, newElement: E): boolean {
266
+ if (index < 0 || index > this.length) return false;
267
+ this._elements.splice(this.offset + index, 0, newElement);
268
+ return true;
269
+ }
270
+
208
271
  /**
209
272
  * Time Complexity: O(1)
210
273
  * Space Complexity: O(1)
211
274
  *
212
- * The function checks if a data structure is empty by comparing its size to zero.
213
- * @returns {boolean} A boolean value indicating whether the size of the object is 0 or not.
275
+ * The function `setAt` updates an element at a specified index in an array-like data structure.
276
+ * @param {number} index - The `index` parameter is a number that represents the position in the
277
+ * array where the new element will be set.
278
+ * @param {E} newElement - The `newElement` parameter represents the new value that you want to set
279
+ * at the specified index in the array.
280
+ * @returns The `setAt` method returns a boolean value - `true` if the element was successfully set
281
+ * at the specified index, and `false` if the index is out of bounds (less than 0 or greater than the
282
+ * length of the array).
214
283
  */
215
- isEmpty(): boolean {
216
- return this.size === 0;
284
+ setAt(index: number, newElement: E): boolean {
285
+ if (index < 0 || index > this.length) return false;
286
+ this._elements[this.offset + index] = newElement;
287
+ return true;
217
288
  }
218
289
 
219
290
  /**
220
291
  * Time Complexity: O(1)
221
- * Space Complexity: O(n)
292
+ * Space Complexity: O(1)
222
293
  *
223
- * The toArray() function returns an array of elements from the current offset to the end of the _elements array.
224
- * @returns An array of type E is being returned.
294
+ * The function checks if a data structure is empty by comparing its length to zero.
295
+ * @returns {boolean} A boolean value indicating whether the length of the object is 0 or not.
225
296
  */
226
- toArray(): E[] {
227
- return this.elements.slice(this.offset);
297
+ isEmpty(): boolean {
298
+ return this.length === 0;
228
299
  }
229
300
 
230
301
  /**
@@ -252,6 +323,40 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
252
323
  return true;
253
324
  }
254
325
 
326
+ /**
327
+ * Time Complexity: O(n)
328
+ * Space Complexity: O(n)
329
+ *
330
+ * The function overrides the splice method to remove and insert elements in a queue-like data
331
+ * structure.
332
+ * @param {number} start - The `start` parameter in the `splice` method specifies the index at which
333
+ * to start changing the array. Items will be added or removed starting from this index.
334
+ * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the
335
+ * number of elements to remove from the array starting at the specified `start` index. If
336
+ * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new
337
+ * elements can still be inserted at
338
+ * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that
339
+ * will be added to the array at the specified `start` index. These elements will replace the
340
+ * existing elements starting from the `start` index for the `deleteCount` number of elements.
341
+ * @returns The `splice` method is returning the `removedQueue`, which is an instance of the same
342
+ * class as the original object.
343
+ */
344
+ override splice(start: number, deleteCount: number = 0, ...items: E[]): this {
345
+ const removedQueue = this._createInstance();
346
+
347
+ start = Math.max(0, Math.min(start, this.length));
348
+ deleteCount = Math.max(0, Math.min(deleteCount, this.length - start));
349
+
350
+ const globalStartIndex = this.offset + start;
351
+
352
+ const removedElements = this._elements.splice(globalStartIndex, deleteCount, ...items);
353
+ removedQueue.pushMany(removedElements);
354
+
355
+ this.compact();
356
+
357
+ return removedQueue;
358
+ }
359
+
255
360
  /**
256
361
  * Time Complexity: O(n)
257
362
  * Space Complexity: O(n)
@@ -259,8 +364,8 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
259
364
  * The `clone()` function returns a new Queue object with the same elements as the original Queue.
260
365
  * @returns The `clone()` method is returning a new instance of the `Queue` class.
261
366
  */
262
- clone(): Queue<E, R> {
263
- return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn });
367
+ clone(): this {
368
+ return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this;
264
369
  }
265
370
 
266
371
  /**
@@ -279,8 +384,12 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
279
384
  * @returns The `filter` method is returning a new `Queue` object that contains the elements that
280
385
  * satisfy the given predicate function.
281
386
  */
282
- filter(predicate: ElementCallback<E, R, boolean, Queue<E, R>>, thisArg?: any): Queue<E, R> {
283
- const newDeque = new Queue<E, R>([], { toElementFn: this.toElementFn });
387
+ filter(predicate: ElementCallback<E, R, boolean>, thisArg?: any): Queue<E, R> {
388
+ const newDeque = this._createInstance({
389
+ toElementFn: this._toElementFn,
390
+ autoCompactRatio: this._autoCompactRatio,
391
+ maxLen: this._maxLen
392
+ });
284
393
  let index = 0;
285
394
  for (const el of this) {
286
395
  if (predicate.call(thisArg, el, index, this)) {
@@ -309,12 +418,12 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
309
418
  * @returns A new Queue object containing elements of type EM, which are the result of applying the
310
419
  * callback function to each element in the original Queue object.
311
420
  */
312
- map<EM, RM>(
313
- callback: ElementCallback<E, R, EM, Queue<E, R>>,
314
- toElementFn?: (rawElement: RM) => EM,
315
- thisArg?: any
316
- ): Queue<EM, RM> {
317
- const newDeque = new Queue<EM, RM>([], { toElementFn });
421
+ map<EM, RM>(callback: ElementCallback<E, R, EM>, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Queue<EM, RM> {
422
+ const newDeque = new Queue<EM, RM>([], {
423
+ toElementFn,
424
+ autoCompactRatio: this._autoCompactRatio,
425
+ maxLen: this._maxLen
426
+ });
318
427
  let index = 0;
319
428
  for (const el of this) {
320
429
  newDeque.push(callback.call(thisArg, el, index, this));
@@ -334,6 +443,30 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
334
443
  yield item;
335
444
  }
336
445
  }
446
+
447
+ /**
448
+ * The function `_createInstance` returns a new instance of the `Queue` class with the specified
449
+ * options.
450
+ * @param [options] - The `options` parameter in the `_createInstance` method is of type
451
+ * `QueueOptions<E, R>`, which is used to configure the behavior of the queue being created. It
452
+ * allows you to specify settings or properties that can influence how the queue operates.
453
+ * @returns An instance of the `Queue` class with an empty array and the provided options is being
454
+ * returned.
455
+ */
456
+ protected override _createInstance(options?: QueueOptions<E, R>): this {
457
+ return new Queue<E, R>([], options) as this;
458
+ }
459
+
460
+ /**
461
+ * The function `_getReverseIterator` returns an iterator that iterates over elements in reverse
462
+ * order.
463
+ */
464
+ protected *_getReverseIterator(): IterableIterator<E> {
465
+ for (let i = this.length - 1; i >= 0; i--) {
466
+ const cur = this.at(i); // `at()` handles the offset.
467
+ if (cur !== undefined) yield cur;
468
+ }
469
+ }
337
470
  }
338
471
 
339
472
  /**
@@ -351,7 +484,7 @@ export class LinkedListQueue<E = any, R = any> extends SinglyLinkedList<E, R> {
351
484
  * @returns The `clone()` method is returning a new instance of `LinkedListQueue` with the same
352
485
  * values as the original `LinkedListQueue`.
353
486
  */
354
- override clone(): LinkedListQueue<E, R> {
355
- return new LinkedListQueue<E, R>(this, { toElementFn: this.toElementFn });
487
+ override clone(): this {
488
+ return new LinkedListQueue<E, R>(this, { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this;
356
489
  }
357
490
  }
@@ -15,8 +15,129 @@ import { IterableElementBase } from '../base';
15
15
  * 4. Function Calls: In most modern programming languages, the records of function calls are managed through a stack. When a function is called, its record (including parameters, local variables, and return address) is 'pushed' into the stack. When the function returns, its record is 'popped' from the stack.
16
16
  * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence.
17
17
  * 6. Backtracking Algorithms: In problems where multiple branches need to be explored but only one branch can be explored at a time, stacks can be used to save the state at each branching point.
18
+ * @example
19
+ * // Balanced Parentheses or Brackets
20
+ * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
21
+ *
22
+ * const stack = new Stack<string>();
23
+ * const input: ValidCharacters[] = '[({})]'.split('') as ValidCharacters[];
24
+ * const matches: { [key in ValidCharacters]?: ValidCharacters } = { ')': '(', ']': '[', '}': '{' };
25
+ * for (const char of input) {
26
+ * if ('([{'.includes(char)) {
27
+ * stack.push(char);
28
+ * } else if (')]}'.includes(char)) {
29
+ * if (stack.pop() !== matches[char]) {
30
+ * fail('Parentheses are not balanced');
31
+ * }
32
+ * }
33
+ * }
34
+ * console.log(stack.isEmpty()); // true
35
+ * @example
36
+ * // Expression Evaluation and Conversion
37
+ * const stack = new Stack<number>();
38
+ * const expression = [5, 3, '+']; // Equivalent to 5 + 3
39
+ * expression.forEach(token => {
40
+ * if (typeof token === 'number') {
41
+ * stack.push(token);
42
+ * } else {
43
+ * const b = stack.pop()!;
44
+ * const a = stack.pop()!;
45
+ * stack.push(token === '+' ? a + b : 0); // Only handling '+' here
46
+ * }
47
+ * });
48
+ * console.log(stack.pop()); // 8
49
+ * @example
50
+ * // Depth-First Search (DFS)
51
+ * const stack = new Stack<number>();
52
+ * const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
53
+ * const visited: number[] = [];
54
+ * stack.push(1);
55
+ * while (!stack.isEmpty()) {
56
+ * const node = stack.pop()!;
57
+ * if (!visited.includes(node)) {
58
+ * visited.push(node);
59
+ * graph[node].forEach(neighbor => stack.push(neighbor));
60
+ * }
61
+ * }
62
+ * console.log(visited); // [1, 3, 5, 2, 4]
63
+ * @example
64
+ * // Backtracking Algorithms
65
+ * const stack = new Stack<[number, number]>();
66
+ * const maze = [
67
+ * ['S', ' ', 'X'],
68
+ * ['X', ' ', 'X'],
69
+ * [' ', ' ', 'E']
70
+ * ];
71
+ * const start: [number, number] = [0, 0];
72
+ * const end = [2, 2];
73
+ * const directions = [
74
+ * [0, 1], // To the right
75
+ * [1, 0], // down
76
+ * [0, -1], // left
77
+ * [-1, 0] // up
78
+ * ];
79
+ *
80
+ * const visited = new Set<string>(); // Used to record visited nodes
81
+ * stack.push(start);
82
+ * const path: number[][] = [];
83
+ *
84
+ * while (!stack.isEmpty()) {
85
+ * const [x, y] = stack.pop()!;
86
+ * if (visited.has(`${x},${y}`)) continue; // Skip already visited nodes
87
+ * visited.add(`${x},${y}`);
88
+ *
89
+ * path.push([x, y]);
90
+ *
91
+ * if (x === end[0] && y === end[1]) {
92
+ * break; // Find the end point and exit
93
+ * }
94
+ *
95
+ * for (const [dx, dy] of directions) {
96
+ * const nx = x + dx;
97
+ * const ny = y + dy;
98
+ * if (
99
+ * maze[nx]?.[ny] === ' ' || // feasible path
100
+ * maze[nx]?.[ny] === 'E' // destination
101
+ * ) {
102
+ * stack.push([nx, ny]);
103
+ * }
104
+ * }
105
+ * }
106
+ *
107
+ * expect(path).toContainEqual(end);
108
+ * @example
109
+ * // Function Call Stack
110
+ * const functionStack = new Stack<string>();
111
+ * functionStack.push('main');
112
+ * functionStack.push('foo');
113
+ * functionStack.push('bar');
114
+ * console.log(functionStack.pop()); // 'bar'
115
+ * console.log(functionStack.pop()); // 'foo'
116
+ * console.log(functionStack.pop()); // 'main'
117
+ * @example
118
+ * // Simplify File Paths
119
+ * const stack = new Stack<string>();
120
+ * const path = '/a/./b/../../c';
121
+ * path.split('/').forEach(segment => {
122
+ * if (segment === '..') stack.pop();
123
+ * else if (segment && segment !== '.') stack.push(segment);
124
+ * });
125
+ * console.log(stack.elements.join('/')); // 'c'
126
+ * @example
127
+ * // Stock Span Problem
128
+ * const stack = new Stack<number>();
129
+ * const prices = [100, 80, 60, 70, 60, 75, 85];
130
+ * const spans: number[] = [];
131
+ * prices.forEach((price, i) => {
132
+ * while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
133
+ * stack.pop();
134
+ * }
135
+ * spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
136
+ * stack.push(i);
137
+ * });
138
+ * console.log(spans); // [1, 1, 1, 2, 1, 4, 6]
18
139
  */
19
- export class Stack<E = any, R = any> extends IterableElementBase<E, R, Stack<E, R>> {
140
+ export class Stack<E = any, R = any> extends IterableElementBase<E, R> {
20
141
  constructor(elements: Iterable<E> | Iterable<R> = [], options?: StackOptions<E, R>) {
21
142
  super(options);
22
143
  this.pushMany(elements);
@@ -153,17 +274,6 @@ export class Stack<E = any, R = any> extends IterableElementBase<E, R, Stack<E,
153
274
  return spliced.length === 1;
154
275
  }
155
276
 
156
- /**
157
- * Time Complexity: O(n)
158
- * Space Complexity: O(n)
159
- *
160
- * The toArray function returns a copy of the elements in an array.
161
- * @returns An array of type E.
162
- */
163
- toArray(): E[] {
164
- return this.elements.slice();
165
- }
166
-
167
277
  /**
168
278
  * Time Complexity: O(1)
169
279
  * Space Complexity: O(1)
@@ -201,7 +311,7 @@ export class Stack<E = any, R = any> extends IterableElementBase<E, R, Stack<E,
201
311
  * @returns The `filter` method is returning a new `Stack` object that contains the elements that
202
312
  * satisfy the given predicate function.
203
313
  */
204
- filter(predicate: ElementCallback<E, R, boolean, Stack<E, R>>, thisArg?: any): Stack<E, R> {
314
+ filter(predicate: ElementCallback<E, R, boolean>, thisArg?: any): Stack<E, R> {
205
315
  const newStack = new Stack<E, R>([], { toElementFn: this.toElementFn });
206
316
  let index = 0;
207
317
  for (const el of this) {
@@ -230,11 +340,7 @@ export class Stack<E = any, R = any> extends IterableElementBase<E, R, Stack<E,
230
340
  * value of
231
341
  * @returns a new Stack object with elements of type EM and raw elements of type RM.
232
342
  */
233
- map<EM, RM>(
234
- callback: ElementCallback<E, R, EM, Stack<E, R>>,
235
- toElementFn?: (rawElement: RM) => EM,
236
- thisArg?: any
237
- ): Stack<EM, RM> {
343
+ map<EM, RM>(callback: ElementCallback<E, R, EM>, toElementFn?: (rawElement: RM) => EM, thisArg?: any): Stack<EM, RM> {
238
344
  const newStack = new Stack<EM, RM>([], { toElementFn });
239
345
  let index = 0;
240
346
  for (const el of this) {
@@ -170,7 +170,7 @@ export class TrieNode {
170
170
  * const subnet = ip.split('.').slice(0, 3).join('.');
171
171
  * console.log(ipRoutingTable.hasPrefix(subnet)); // true
172
172
  */
173
- export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
173
+ export class Trie<R = any> extends IterableElementBase<string, R> {
174
174
  /**
175
175
  * The constructor initializes a Trie data structure with optional options and words provided as
176
176
  * input.
@@ -545,7 +545,7 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
545
545
  * specific object as the context for the `predicate` function. If `thisArg` is provided, it will be
546
546
  * @returns The `filter` method is returning an array of strings (`string[]`).
547
547
  */
548
- filter(predicate: ElementCallback<string, R, boolean, Trie<R>>, thisArg?: any): Trie<R> {
548
+ filter(predicate: ElementCallback<string, R, boolean>, thisArg?: any): Trie<R> {
549
549
  const results = new Trie<R>([], { toElementFn: this.toElementFn, caseSensitive: this.caseSensitive });
550
550
  let index = 0;
551
551
  for (const word of this) {
@@ -576,7 +576,7 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
576
576
  * @returns a new Trie object.
577
577
  */
578
578
  map<RM>(
579
- callback: ElementCallback<string, R, string, Trie<R>>,
579
+ callback: ElementCallback<string, R, string>,
580
580
  toElementFn?: (rawElement: RM) => string,
581
581
  thisArg?: any
582
582
  ): Trie<RM> {
@@ -609,6 +609,10 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
609
609
  yield* _dfs(this.root, '');
610
610
  }
611
611
 
612
+ protected get _total() {
613
+ return this._size;
614
+ }
615
+
612
616
  /**
613
617
  * Time Complexity: O(l), where l is the length of the input string.
614
618
  * Space Complexity: O(1) - Constant space.
@@ -1,25 +1,34 @@
1
1
  import { IterableElementBase, IterableEntryBase } from '../../../data-structures';
2
+ import { LinearBase } from '../../../data-structures/base/linear-base';
2
3
 
3
- export type EntryCallback<K, V, R> = (key: K, value: V, index: number, container: IterableEntryBase<K, V>) => R;
4
- export type ElementCallback<E, R, RT, C> = (element: E, index: number, container: IterableElementBase<E, R, C>) => RT;
4
+ export type EntryCallback<K, V, R> = (key: K, value: V, index: number, original: IterableEntryBase<K, V>) => R;
5
+ export type ElementCallback<E, R, RT> = (element: E, index: number, original: IterableElementBase<E, R>) => RT;
5
6
  export type ReduceEntryCallback<K, V, R> = (
6
7
  accumulator: R,
7
8
  value: V,
8
9
  key: K,
9
10
  index: number,
10
- container: IterableEntryBase<K, V>
11
+ original: IterableEntryBase<K, V>
11
12
  ) => R;
12
- export type ReduceElementCallback<E, R, RT, C> = (
13
+
14
+ export type ReduceElementCallback<E, R, RT = E> = (
13
15
  accumulator: RT,
14
16
  element: E,
15
17
  index: number,
16
- container: IterableElementBase<E, R, C>
18
+ original: IterableElementBase<E, R>
17
19
  ) => RT;
18
20
 
19
- // export type IterableEntryBaseOptions<K, V, R> = {
20
- // toEntryFn?: (rawElement: R) => BTNEntry<K, V>;
21
- // };
21
+ export type ReduceLinearCallback<E, RT = E> = (
22
+ accumulator: RT,
23
+ element: E,
24
+ index: number,
25
+ original: LinearBase<E>
26
+ ) => RT;
22
27
 
23
28
  export type IterableElementBaseOptions<E, R> = {
24
29
  toElementFn?: (rawElement: R) => E;
25
30
  };
31
+
32
+ export type LinearBaseOptions<E, R> = IterableElementBaseOptions<E, R> & {
33
+ maxLen?: number;
34
+ };
@@ -1,3 +1,3 @@
1
1
  import type { AVLTreeOptions } from './avl-tree';
2
2
 
3
- export type AVLTreeMultiMapOptions<K, V, R> = Omit<AVLTreeOptions<K, V, R>, 'isMapMode'> & {}
3
+ export type AVLTreeMultiMapOptions<K, V, R> = AVLTreeOptions<K, V, R> & {}
@@ -1,3 +1,3 @@
1
1
  import type { RedBlackTreeOptions } from './red-black-tree';
2
2
 
3
- export type TreeMultiMapOptions<K, V, R> = Omit<RedBlackTreeOptions<K, V, R>, 'isMapMode'> & {}
3
+ export type TreeMultiMapOptions<K, V, R> = RedBlackTreeOptions<K, V, R> & {}
@@ -1,3 +1,3 @@
1
- import { IterableElementBaseOptions } from '../base';
1
+ import { LinearBaseOptions } from '../base';
2
2
 
3
- export type DoublyLinkedListOptions<E, R> = IterableElementBaseOptions<E, R> & {};
3
+ export type DoublyLinkedListOptions<E, R> = LinearBaseOptions<E, R> & {};
@@ -1,3 +1,3 @@
1
- import { IterableElementBaseOptions } from '../base';
1
+ import { LinearBaseOptions } from '../base';
2
2
 
3
- export type SinglyLinkedListOptions<E, R> = IterableElementBaseOptions<E, R> & {};
3
+ export type SinglyLinkedListOptions<E, R> = LinearBaseOptions<E, R> & {};
@@ -1,6 +1,5 @@
1
- import { IterableElementBaseOptions } from '../base';
1
+ import { LinearBaseOptions } from '../base';
2
2
 
3
3
  export type DequeOptions<E, R> = {
4
4
  bucketSize?: number;
5
- maxLen?: number;
6
- } & IterableElementBaseOptions<E, R>;
5
+ } & LinearBaseOptions<E, R>;