min-heap-typed 2.0.5 → 2.1.0

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 (101) hide show
  1. package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
  2. package/dist/data-structures/base/iterable-element-base.js +149 -107
  3. package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
  4. package/dist/data-structures/base/iterable-entry-base.js +59 -116
  5. package/dist/data-structures/base/linear-base.d.ts +250 -192
  6. package/dist/data-structures/base/linear-base.js +137 -274
  7. package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  8. package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
  9. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  10. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
  11. package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
  12. package/dist/data-structures/binary-tree/avl-tree.js +208 -195
  13. package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
  14. package/dist/data-structures/binary-tree/binary-tree.js +598 -869
  15. package/dist/data-structures/binary-tree/bst.d.ts +258 -306
  16. package/dist/data-structures/binary-tree/bst.js +505 -481
  17. package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  18. package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
  19. package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
  20. package/dist/data-structures/binary-tree/tree-counter.js +172 -203
  21. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  22. package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
  23. package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
  24. package/dist/data-structures/graph/abstract-graph.js +267 -237
  25. package/dist/data-structures/graph/directed-graph.d.ts +108 -224
  26. package/dist/data-structures/graph/directed-graph.js +146 -233
  27. package/dist/data-structures/graph/map-graph.d.ts +49 -55
  28. package/dist/data-structures/graph/map-graph.js +56 -59
  29. package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
  30. package/dist/data-structures/graph/undirected-graph.js +129 -149
  31. package/dist/data-structures/hash/hash-map.d.ts +164 -338
  32. package/dist/data-structures/hash/hash-map.js +270 -457
  33. package/dist/data-structures/heap/heap.d.ts +214 -289
  34. package/dist/data-structures/heap/heap.js +340 -349
  35. package/dist/data-structures/heap/max-heap.d.ts +11 -47
  36. package/dist/data-structures/heap/max-heap.js +11 -66
  37. package/dist/data-structures/heap/min-heap.d.ts +12 -47
  38. package/dist/data-structures/heap/min-heap.js +11 -66
  39. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  40. package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
  41. package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  42. package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
  43. package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  44. package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
  45. package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  46. package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
  47. package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  48. package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
  49. package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
  50. package/dist/data-structures/priority-queue/priority-queue.js +8 -83
  51. package/dist/data-structures/queue/deque.d.ts +227 -254
  52. package/dist/data-structures/queue/deque.js +309 -348
  53. package/dist/data-structures/queue/queue.d.ts +180 -201
  54. package/dist/data-structures/queue/queue.js +265 -248
  55. package/dist/data-structures/stack/stack.d.ts +124 -102
  56. package/dist/data-structures/stack/stack.js +181 -125
  57. package/dist/data-structures/trie/trie.d.ts +164 -165
  58. package/dist/data-structures/trie/trie.js +189 -172
  59. package/dist/interfaces/binary-tree.d.ts +56 -6
  60. package/dist/interfaces/graph.d.ts +16 -0
  61. package/dist/types/data-structures/base/base.d.ts +1 -1
  62. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
  63. package/dist/types/utils/utils.d.ts +1 -0
  64. package/dist/utils/utils.d.ts +1 -1
  65. package/dist/utils/utils.js +2 -1
  66. package/package.json +2 -2
  67. package/src/data-structures/base/iterable-element-base.ts +238 -115
  68. package/src/data-structures/base/iterable-entry-base.ts +96 -120
  69. package/src/data-structures/base/linear-base.ts +271 -277
  70. package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
  71. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
  72. package/src/data-structures/binary-tree/avl-tree.ts +239 -206
  73. package/src/data-structures/binary-tree/binary-tree.ts +664 -893
  74. package/src/data-structures/binary-tree/bst.ts +568 -570
  75. package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
  76. package/src/data-structures/binary-tree/tree-counter.ts +199 -218
  77. package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
  78. package/src/data-structures/graph/abstract-graph.ts +339 -264
  79. package/src/data-structures/graph/directed-graph.ts +146 -236
  80. package/src/data-structures/graph/map-graph.ts +63 -60
  81. package/src/data-structures/graph/undirected-graph.ts +129 -152
  82. package/src/data-structures/hash/hash-map.ts +274 -496
  83. package/src/data-structures/heap/heap.ts +389 -402
  84. package/src/data-structures/heap/max-heap.ts +12 -76
  85. package/src/data-structures/heap/min-heap.ts +13 -76
  86. package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
  87. package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
  88. package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
  89. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
  90. package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
  91. package/src/data-structures/priority-queue/priority-queue.ts +3 -92
  92. package/src/data-structures/queue/deque.ts +381 -357
  93. package/src/data-structures/queue/queue.ts +310 -264
  94. package/src/data-structures/stack/stack.ts +217 -131
  95. package/src/data-structures/trie/trie.ts +240 -175
  96. package/src/interfaces/binary-tree.ts +240 -6
  97. package/src/interfaces/graph.ts +37 -0
  98. package/src/types/data-structures/base/base.ts +5 -5
  99. package/src/types/data-structures/graph/abstract-graph.ts +5 -0
  100. package/src/types/utils/utils.ts +2 -0
  101. package/src/utils/utils.ts +9 -14
@@ -1,13 +1,20 @@
1
1
  /**
2
- * @license MIT
3
- * @copyright Pablo Zeng <zrwusa@gmail.com>
4
- * @class
2
+ * data-structure-typed
3
+ *
4
+ * @author Pablo Zeng
5
+ * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
+ * @license MIT License
5
7
  */
6
- import type { ElementCallback, QueueOptions } from '../../types';
8
+
9
+ import type { ElementCallback, LinearBaseOptions, QueueOptions } from '../../types';
7
10
  import { SinglyLinkedList } from '../linked-list';
8
11
  import { LinearBase } from '../base/linear-base';
9
12
 
10
13
  /**
14
+ * Array-backed queue with amortized O(1) enqueue/dequeue via an offset pointer and optional auto-compaction.
15
+ * @remarks Time O(1), Space O(1)
16
+ * @template E
17
+ * @template R
11
18
  * 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.
12
19
  * 2. Operations: The main operations include enqueue (adding an element to the end of the queue) and dequeue (removing and returning the element at the front of the queue). Typically, there is also a peek operation (looking at the front element without removing it).
13
20
  * 3. Uses: Queues are commonly used to manage a series of tasks or elements that need to be processed in order. For example, managing task queues in a multi-threaded environment, or in algorithms for data structures like trees and graphs for breadth-first search.
@@ -24,7 +31,7 @@ import { LinearBase } from '../base/linear-base';
24
31
  * let maxSum = 0;
25
32
  * let currentSum = 0;
26
33
  *
27
- * nums.forEach((num) => {
34
+ * nums.forEach(num => {
28
35
  * queue.push(num);
29
36
  * currentSum += num;
30
37
  *
@@ -64,89 +71,129 @@ import { LinearBase } from '../base/linear-base';
64
71
  * console.log(visited); // [1, 2, 3, 4, 5]
65
72
  */
66
73
  export class Queue<E = any, R = any> extends LinearBase<E, R> {
74
+ /**
75
+ * Create a Queue and optionally bulk-insert elements.
76
+ * @remarks Time O(N), Space O(N)
77
+ * @param [elements] - Iterable of elements (or raw records if toElementFn is set).
78
+ * @param [options] - Options such as toElementFn, maxLen, and autoCompactRatio.
79
+ * @returns New Queue instance.
80
+ */
81
+
67
82
  constructor(elements: Iterable<E> | Iterable<R> = [], options?: QueueOptions<E, R>) {
68
83
  super(options);
69
-
70
84
  if (options) {
71
85
  const { autoCompactRatio = 0.5 } = options;
72
86
  this._autoCompactRatio = autoCompactRatio;
73
87
  }
74
-
75
88
  this.pushMany(elements);
76
89
  }
77
90
 
78
91
  protected _elements: E[] = [];
79
92
 
93
+ /**
94
+ * Get the underlying array buffer.
95
+ * @remarks Time O(1), Space O(1)
96
+ * @returns Backing array of elements.
97
+ */
98
+
80
99
  get elements(): E[] {
81
100
  return this._elements;
82
101
  }
83
102
 
84
- protected _offset: number = 0;
103
+ protected _offset = 0;
104
+
105
+ /**
106
+ * Get the current start offset into the array.
107
+ * @remarks Time O(1), Space O(1)
108
+ * @returns Zero-based offset.
109
+ */
85
110
 
86
111
  get offset(): number {
87
112
  return this._offset;
88
113
  }
89
114
 
90
- get length(): number {
91
- return this.elements.length - this.offset;
92
- }
115
+ protected _autoCompactRatio = 0.5;
93
116
 
94
- protected _autoCompactRatio: number = 0.5;
117
+ /**
118
+ * Get the compaction threshold (offset/size).
119
+ * @remarks Time O(1), Space O(1)
120
+ * @returns Auto-compaction ratio in (0,1].
121
+ */
95
122
 
96
123
  get autoCompactRatio(): number {
97
124
  return this._autoCompactRatio;
98
125
  }
99
126
 
100
- set autoCompactRatio(v: number) {
101
- this._autoCompactRatio = v;
127
+ /**
128
+ * Set the compaction threshold.
129
+ * @remarks Time O(1), Space O(1)
130
+ * @param value - New ratio; compacts when offset/size exceeds this value.
131
+ * @returns void
132
+ */
133
+
134
+ set autoCompactRatio(value: number) {
135
+ this._autoCompactRatio = value;
102
136
  }
103
137
 
104
138
  /**
105
- * Time Complexity: O(1)
106
- * Space Complexity: O(1)
107
- *
108
- * The `first` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
109
- * @returns The `get first()` method returns the first element of the data structure, represented by the `_elements` array at
110
- * the `_offset` index. If the data structure is empty (length is 0), it returns `undefined`.
139
+ * Get the number of elements currently in the queue.
140
+ * @remarks Time O(1), Space O(1)
141
+ * @returns Current length.
111
142
  */
143
+
144
+ get length(): number {
145
+ return this.elements.length - this._offset;
146
+ }
147
+
148
+ /**
149
+ * Get the first element (front) without removing it.
150
+ * @remarks Time O(1), Space O(1)
151
+ * @returns Front element or undefined.
152
+ */
153
+
112
154
  get first(): E | undefined {
113
- return this.length > 0 ? this.elements[this.offset] : undefined;
155
+ return this.length > 0 ? this.elements[this._offset] : undefined;
114
156
  }
115
157
 
116
158
  /**
117
- * Time Complexity: O(1)
118
- * Space Complexity: O(1)
119
- *
120
- * The `last` function returns the last element in an array-like data structure, or undefined if the structure is empty.
121
- * @returns The method `get last()` returns the last element of the `_elements` array if the array is not empty. If the
122
- * array is empty, it returns `undefined`.
159
+ * Get the last element (back) without removing it.
160
+ * @remarks Time O(1), Space O(1)
161
+ * @returns Back element or undefined.
123
162
  */
163
+
124
164
  get last(): E | undefined {
125
165
  return this.length > 0 ? this.elements[this.elements.length - 1] : undefined;
126
166
  }
127
167
 
128
168
  /**
129
- * Time Complexity: O(n)
130
- * Space Complexity: O(n)
131
- *
132
- * The function "fromArray" creates a new Queue object from an array of elements.Creates a queue from an existing array.
133
- * @public
134
- * @param {E[]} elements - The "elements" parameter is an array of elements of type E.
135
- * @returns The method is returning a new instance of the Queue class, initialized with the elements from the input
136
- * array.
169
+ * Create a queue from an array of elements.
170
+ * @remarks Time O(N), Space O(N)
171
+ * @template E
172
+ * @param elements - Array of elements to enqueue in order.
173
+ * @returns A new queue populated from the array.
137
174
  */
175
+
138
176
  static fromArray<E>(elements: E[]): Queue<E> {
139
177
  return new Queue(elements);
140
178
  }
141
179
 
142
180
  /**
143
- * Time Complexity: O(1)
144
- * Space Complexity: O(1)
145
- *
146
- * The push function adds an element to the end of the queue and returns true. Adds an element at the back of the queue.
147
- * @param {E} element - The `element` parameter represents the element that you want to add to the queue.
148
- * @returns Always returns true, indicating the element was successfully added.
181
+ * Check whether the queue is empty.
182
+ * @remarks Time O(1), Space O(1)
183
+ * @returns True if length is 0.
149
184
  */
185
+
186
+ isEmpty(): boolean {
187
+ return this.length === 0;
188
+ }
189
+
190
+ /**
191
+ * Enqueue one element at the back.
192
+ * @remarks Time O(1), Space O(1)
193
+ * @param element - Element to enqueue.
194
+ * @returns True on success.
195
+ */
196
+
150
197
  push(element: E): boolean {
151
198
  this.elements.push(element);
152
199
  if (this._maxLen > 0 && this.length > this._maxLen) this.shift();
@@ -154,17 +201,13 @@ export class Queue<E = any, R = any> extends LinearBase<E, R> {
154
201
  }
155
202
 
156
203
  /**
157
- * Time Complexity: O(k)
158
- * Space Complexity: O(k)
159
- *
160
- * The `pushMany` function iterates over elements and pushes them into an array after applying a
161
- * transformation function if provided.
162
- * @param {Iterable<E> | Iterable<R>} elements - The `elements` parameter in the `pushMany` function
163
- * is an iterable containing elements of type `E` or `R`.
164
- * @returns The `pushMany` function is returning an array of boolean values indicating whether each
165
- * element was successfully pushed into the data structure.
204
+ * Enqueue many elements from an iterable.
205
+ * @remarks Time O(N), Space O(1)
206
+ * @param elements - Iterable of elements (or raw records if toElementFn is set).
207
+ * @returns Array of per-element success flags.
166
208
  */
167
- pushMany(elements: Iterable<E> | Iterable<R>) {
209
+
210
+ pushMany(elements: Iterable<E> | Iterable<R>): boolean[] {
168
211
  const ans: boolean[] = [];
169
212
  for (const el of elements) {
170
213
  if (this.toElementFn) ans.push(this.push(this.toElementFn(el as R)));
@@ -174,317 +217,320 @@ export class Queue<E = any, R = any> extends LinearBase<E, R> {
174
217
  }
175
218
 
176
219
  /**
177
- * Time Complexity: O(1)
178
- * Space Complexity: O(1)
179
- *
180
- * The `shift` function removes and returns the first element in the queue, and adjusts the internal data structure if
181
- * necessary to optimize performance.
182
- * @returns The function `shift()` returns either the first element in the queue or `undefined` if the queue is empty.
220
+ * Dequeue one element from the front (amortized via offset).
221
+ * @remarks Time O(1) amortized, Space O(1)
222
+ * @returns Removed element or undefined.
183
223
  */
224
+
184
225
  shift(): E | undefined {
185
226
  if (this.length === 0) return undefined;
186
-
187
227
  const first = this.first;
188
228
  this._offset += 1;
189
-
190
- if (this.offset / this.elements.length > this.autoCompactRatio) this.compact();
229
+ if (this.elements.length > 0 && this.offset / this.elements.length > this.autoCompactRatio) this.compact();
191
230
  return first;
192
231
  }
193
232
 
194
233
  /**
195
- * Time Complexity: O(n)
196
- * Space Complexity: O(1)
197
- *
198
- * The delete function removes an element from the list.
199
- * @param {E} element - Specify the element to be deleted
200
- * @return A boolean value indicating whether the element was successfully deleted or not
234
+ * Delete the first occurrence of a specific element.
235
+ * @remarks Time O(N), Space O(1)
236
+ * @param element - Element to remove (strict equality via Object.is).
237
+ * @returns True if an element was removed.
201
238
  */
239
+
202
240
  delete(element: E): boolean {
203
- const index = this.elements.indexOf(element);
204
- return !!this.deleteAt(index);
241
+ for (let i = this._offset; i < this.elements.length; i++) {
242
+ if (Object.is(this.elements[i], element)) {
243
+ this.elements.splice(i, 1);
244
+ return true;
245
+ }
246
+ }
247
+ return false;
205
248
  }
206
249
 
207
250
  /**
208
- * Time Complexity: O(n)
209
- * Space Complexity: O(1)
210
- *
211
- * The deleteAt function deletes the element at a given index.
212
- * @param {number} index - Determine the index of the element to be deleted
213
- * @return A boolean value
251
+ * Get the element at a given logical index.
252
+ * @remarks Time O(1), Space O(1)
253
+ * @param index - Zero-based index from the front.
254
+ * @returns Element or undefined.
214
255
  */
215
- deleteAt(index: number): E | undefined {
216
- const deleted = this.elements[index];
217
- this.elements.splice(index, 1);
218
- return deleted;
219
- }
220
256
 
221
- /**
222
- * Time Complexity: O(1)
223
- * Space Complexity: O(1)
224
- *
225
- * The `at` function returns the element at a specified index adjusted by an offset, or `undefined`
226
- * if the index is out of bounds.
227
- * @param {number} index - The `index` parameter represents the position of the element you want to
228
- * retrieve from the data structure.
229
- * @returns The `at` method is returning the element at the specified index adjusted by the offset
230
- * `_offset`.
231
- */
232
257
  at(index: number): E | undefined {
233
- return this.elements[index + this._offset];
258
+ if (index < 0 || index >= this.length) return undefined;
259
+ return this._elements[this._offset + index];
234
260
  }
235
261
 
236
262
  /**
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.
263
+ * Delete the element at a given index.
264
+ * @remarks Time O(N), Space O(1)
265
+ * @param index - Zero-based index from the front.
266
+ * @returns Removed element or undefined.
244
267
  */
245
- reverse(): this {
246
- this._elements = this.elements.slice(this.offset).reverse();
247
- this._offset = 0;
248
- return this;
268
+
269
+ deleteAt(index: number): E | undefined {
270
+ if (index < 0 || index >= this.length) return undefined;
271
+ const gi = this._offset + index;
272
+ const [deleted] = this.elements.splice(gi, 1);
273
+ return deleted;
249
274
  }
250
275
 
251
276
  /**
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).
277
+ * Insert a new element at a given index.
278
+ * @remarks Time O(N), Space O(1)
279
+ * @param index - Zero-based index from the front.
280
+ * @param newElement - Element to insert.
281
+ * @returns True if inserted.
264
282
  */
283
+
265
284
  addAt(index: number, newElement: E): boolean {
266
285
  if (index < 0 || index > this.length) return false;
267
- this._elements.splice(this.offset + index, 0, newElement);
286
+ this._elements.splice(this._offset + index, 0, newElement);
268
287
  return true;
269
288
  }
270
289
 
271
290
  /**
272
- * Time Complexity: O(1)
273
- * Space Complexity: O(1)
274
- *
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).
291
+ * Replace the element at a given index.
292
+ * @remarks Time O(1), Space O(1)
293
+ * @param index - Zero-based index from the front.
294
+ * @param newElement - New element to set.
295
+ * @returns True if updated.
283
296
  */
297
+
284
298
  setAt(index: number, newElement: E): boolean {
285
- if (index < 0 || index > this.length) return false;
286
- this._elements[this.offset + index] = newElement;
299
+ if (index < 0 || index >= this.length) return false;
300
+ this._elements[this._offset + index] = newElement;
287
301
  return true;
288
302
  }
289
303
 
290
304
  /**
291
- * Time Complexity: O(1)
292
- * Space Complexity: O(1)
293
- *
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.
305
+ * Reverse the queue in-place by compacting then reversing.
306
+ * @remarks Time O(N), Space O(N)
307
+ * @returns This queue.
296
308
  */
297
- isEmpty(): boolean {
298
- return this.length === 0;
309
+
310
+ reverse(): this {
311
+ this._elements = this.elements.slice(this._offset).reverse();
312
+ this._offset = 0;
313
+ return this;
299
314
  }
300
315
 
301
316
  /**
302
- * Time Complexity: O(1)
303
- * Space Complexity: O(1)
304
- *
305
- * The clear function resets the elements array and offset to their initial values.
317
+ * Remove all elements and reset offset.
318
+ * @remarks Time O(1), Space O(1)
319
+ * @returns void
306
320
  */
321
+
307
322
  clear(): void {
308
323
  this._elements = [];
309
324
  this._offset = 0;
310
325
  }
311
326
 
312
327
  /**
313
- * Time Complexity: O(n)
314
- * Space Complexity: O(1)
315
- *
316
- * The `compact` function in TypeScript slices the elements array based on the offset and resets the
317
- * offset to zero.
318
- * @returns The `compact()` method is returning a boolean value of `true`.
328
+ * Compact storage by discarding consumed head elements.
329
+ * @remarks Time O(N), Space O(N)
330
+ * @returns True when compaction performed.
319
331
  */
332
+
320
333
  compact(): boolean {
321
- this._elements = this.elements.slice(this.offset);
334
+ this._elements = this.elements.slice(this._offset);
322
335
  this._offset = 0;
323
336
  return true;
324
337
  }
325
338
 
326
339
  /**
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.
340
+ * Remove and/or insert elements at a position (array-like).
341
+ * @remarks Time O(N + M), Space O(M)
342
+ * @param start - Start index (clamped to [0, length]).
343
+ * @param [deleteCount] - Number of elements to remove (default 0).
344
+ * @param [items] - Elements to insert after `start`.
345
+ * @returns A new queue containing the removed elements (typed as `this`).
343
346
  */
344
- override splice(start: number, deleteCount: number = 0, ...items: E[]): this {
345
- const removedQueue = this._createInstance();
346
347
 
348
+ override splice(start: number, deleteCount: number = 0, ...items: E[]): this {
347
349
  start = Math.max(0, Math.min(start, this.length));
348
350
  deleteCount = Math.max(0, Math.min(deleteCount, this.length - start));
349
351
 
350
- const globalStartIndex = this.offset + start;
352
+ const gi = this._offset + start;
353
+ const removedArray = this._elements.splice(gi, deleteCount, ...items);
351
354
 
352
- const removedElements = this._elements.splice(globalStartIndex, deleteCount, ...items);
353
- removedQueue.pushMany(removedElements);
355
+ if (this.elements.length > 0 && this.offset / this.elements.length > this.autoCompactRatio) this.compact();
354
356
 
355
- this.compact();
357
+ const removed = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
358
+ removed._setAutoCompactRatio(this._autoCompactRatio);
359
+ removed.pushMany(removedArray);
356
360
 
357
- return removedQueue;
361
+ return removed as unknown as this;
358
362
  }
359
363
 
360
364
  /**
361
- * Time Complexity: O(n)
362
- * Space Complexity: O(n)
363
- *
364
- * The `clone()` function returns a new Queue object with the same elements as the original Queue.
365
- * @returns The `clone()` method is returning a new instance of the `Queue` class.
365
+ * Deep clone this queue and its parameters.
366
+ * @remarks Time O(N), Space O(N)
367
+ * @returns A new queue with the same content and options.
366
368
  */
369
+
367
370
  clone(): this {
368
- return new Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this;
369
- }
370
-
371
- /**
372
- * Time Complexity: O(n)
373
- * Space Complexity: O(n)
374
- *
375
- * The `filter` function creates a new `Queue` object containing elements from the original `Queue`
376
- * that satisfy a given predicate function.
377
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
378
- * the current element being iterated over, the index of the current element, and the queue itself.
379
- * It should return a boolean value indicating whether the element should be included in the filtered
380
- * queue or not.
381
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
382
- * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
383
- * passed as the `this` value to the `predicate` function. If `thisArg` is
384
- * @returns The `filter` method is returning a new `Queue` object that contains the elements that
385
- * satisfy the given predicate function.
386
- */
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
- });
371
+ const out = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
372
+ out._setAutoCompactRatio(this._autoCompactRatio);
373
+ for (let i = this._offset; i < this.elements.length; i++) out.push(this.elements[i]);
374
+ return out;
375
+ }
376
+
377
+ /**
378
+ * Filter elements into a new queue of the same class.
379
+ * @remarks Time O(N), Space O(N)
380
+ * @param predicate - Predicate (element, index, queue) boolean to keep element.
381
+ * @param [thisArg] - Value for `this` inside the predicate.
382
+ * @returns A new queue with kept elements.
383
+ */
384
+
385
+ filter(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): this {
386
+ const out = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
387
+ out._setAutoCompactRatio(this._autoCompactRatio);
393
388
  let index = 0;
394
- for (const el of this) {
395
- if (predicate.call(thisArg, el, index, this)) {
396
- newDeque.push(el);
397
- }
389
+ for (const v of this) {
390
+ if (predicate.call(thisArg, v, index, this)) out.push(v);
398
391
  index++;
399
392
  }
400
- return newDeque;
401
- }
402
-
403
- /**
404
- * Time Complexity: O(n)
405
- * Space Complexity: O(n)
406
- *
407
- * The `map` function in TypeScript creates a new Queue by applying a callback function to each
408
- * element in the original Queue.
409
- * @param callback - The `callback` parameter is a function that will be applied to each element in
410
- * the queue. It takes the current element, its index, and the queue itself as arguments, and returns
411
- * a new element.
412
- * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be provided to
413
- * convert a raw element of type `RM` to a new element of type `EM`. This function is used within the
414
- * `map` method to transform each raw element before passing it to the `callback` function. If
415
- * @param {any} [thisArg] - The `thisArg` parameter in the `map` function is used to specify the
416
- * value of `this` when executing the `callback` function. It allows you to set the context (the
417
- * value of `this`) within the callback function. If `thisArg` is provided, it will be
418
- * @returns A new Queue object containing elements of type EM, which are the result of applying the
419
- * callback function to each element in the original Queue object.
420
- */
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
393
+ return out;
394
+ }
395
+
396
+ /**
397
+ * Map each element to a new element in a possibly different-typed queue.
398
+ * @remarks Time O(N), Space O(N)
399
+ * @template EM
400
+ * @template RM
401
+ * @param callback - Mapping function (element, index, queue) newElement.
402
+ * @param [options] - Options for the output queue (e.g., toElementFn, maxLen, autoCompactRatio).
403
+ * @param [thisArg] - Value for `this` inside the callback.
404
+ * @returns A new Queue with mapped elements.
405
+ */
406
+
407
+ map<EM, RM>(callback: ElementCallback<E, R, EM>, options?: QueueOptions<EM, RM>, thisArg?: unknown): Queue<EM, RM> {
408
+ const out = new (this.constructor as new (
409
+ elements?: Iterable<EM> | Iterable<RM>,
410
+ options?: QueueOptions<EM, RM>
411
+ ) => Queue<EM, RM>)([], {
412
+ toElementFn: options?.toElementFn,
413
+ maxLen: options?.maxLen ?? this._maxLen,
414
+ autoCompactRatio: options?.autoCompactRatio ?? this._autoCompactRatio
426
415
  });
427
416
  let index = 0;
428
- for (const el of this) {
429
- newDeque.push(callback.call(thisArg, el, index, this));
430
- index++;
431
- }
432
- return newDeque;
417
+ for (const v of this)
418
+ out.push(thisArg === undefined ? callback(v, index++, this) : callback.call(thisArg, v, index++, this));
419
+ return out;
433
420
  }
434
421
 
435
422
  /**
436
- * Time Complexity: O(n)
437
- * Space Complexity: O(n)
438
- *
439
- * The function `_getIterator` returns an iterable iterator for the elements in the class.
423
+ * Map each element to a new value of the same type.
424
+ * @remarks Time O(N), Space O(N)
425
+ * @param callback - Mapping function (element, index, queue) → element.
426
+ * @param [thisArg] - Value for `this` inside the callback.
427
+ * @returns A new queue with mapped elements (same element type).
440
428
  */
441
- protected *_getIterator(): IterableIterator<E> {
442
- for (const item of this.elements.slice(this.offset)) {
443
- yield item;
429
+
430
+ mapSame(callback: ElementCallback<E, R, E>, thisArg?: unknown): this {
431
+ const Ctor = this.constructor as new (
432
+ elements?: Iterable<E> | Iterable<R>,
433
+ options?: QueueOptions<E, R>
434
+ ) => Queue<E, R>;
435
+ const out = new Ctor([], {
436
+ toElementFn: this.toElementFn,
437
+ maxLen: this._maxLen,
438
+ autoCompactRatio: this._autoCompactRatio
439
+ });
440
+ out._setAutoCompactRatio?.(this._autoCompactRatio);
441
+ let index = 0;
442
+ for (const v of this) {
443
+ const mv = thisArg === undefined ? callback(v, index++, this) : callback.call(thisArg, v, index++, this);
444
+ out.push(mv);
444
445
  }
446
+ return out as this;
445
447
  }
446
448
 
447
449
  /**
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.
450
+ * (Protected) Set the internal auto-compaction ratio.
451
+ * @remarks Time O(1), Space O(1)
452
+ * @param value - New ratio to assign.
453
+ * @returns void
455
454
  */
456
- protected override _createInstance(options?: QueueOptions<E, R>): this {
457
- return new Queue<E, R>([], options) as this;
455
+
456
+ protected _setAutoCompactRatio(value: number): void {
457
+ this._autoCompactRatio = value;
458
+ }
459
+
460
+ /**
461
+ * (Protected) Iterate elements from front to back.
462
+ * @remarks Time O(N), Space O(1)
463
+ * @returns Iterator of E.
464
+ */
465
+
466
+ protected *_getIterator(): IterableIterator<E> {
467
+ for (let i = this._offset; i < this.elements.length; i++) yield this.elements[i];
458
468
  }
459
469
 
460
470
  /**
461
- * The function `_getReverseIterator` returns an iterator that iterates over elements in reverse
462
- * order.
471
+ * (Protected) Iterate elements from back to front.
472
+ * @remarks Time O(N), Space O(1)
473
+ * @returns Iterator of E.
463
474
  */
475
+
464
476
  protected *_getReverseIterator(): IterableIterator<E> {
465
477
  for (let i = this.length - 1; i >= 0; i--) {
466
- const cur = this.at(i); // `at()` handles the offset.
478
+ const cur = this.at(i);
467
479
  if (cur !== undefined) yield cur;
468
480
  }
469
481
  }
482
+
483
+ /**
484
+ * (Protected) Create an empty instance of the same concrete class.
485
+ * @remarks Time O(1), Space O(1)
486
+ * @param [options] - Options forwarded to the constructor.
487
+ * @returns An empty like-kind queue instance.
488
+ */
489
+
490
+ protected override _createInstance(options?: LinearBaseOptions<E, R>): this {
491
+ const Ctor = this.constructor as new (elements?: Iterable<E> | Iterable<R>, options?: QueueOptions<E, R>) => this;
492
+ return new Ctor([], options as QueueOptions<E, R> | undefined);
493
+ }
494
+
495
+ /**
496
+ * (Protected) Create a like-kind queue and seed it from an iterable.
497
+ * @remarks Time O(N), Space O(N)
498
+ * @template EM
499
+ * @template RM
500
+ * @param [elements] - Iterable used to seed the new queue.
501
+ * @param [options] - Options forwarded to the constructor.
502
+ * @returns A like-kind Queue instance.
503
+ */
504
+
505
+ protected _createLike<EM = E, RM = R>(
506
+ elements: Iterable<EM> | Iterable<RM> = [],
507
+ options?: QueueOptions<EM, RM>
508
+ ): Queue<EM, RM> {
509
+ const Ctor = this.constructor as new (
510
+ elements?: Iterable<EM> | Iterable<RM>,
511
+ options?: QueueOptions<EM, RM>
512
+ ) => Queue<EM, RM>;
513
+ return new Ctor(elements, options);
514
+ }
470
515
  }
471
516
 
472
517
  /**
473
- * 1. First In, First Out (FIFO) Strategy: Like other queue implementations, LinkedListQueue follows the first in, first out principle, meaning the element that is added to the queue first will be the first to be removed.
474
- * 2. Based on Linked List: LinkedListQueue uses a linked list to store elements. Each node in the linked list contains data and a pointer to the next node.
475
- * 3. Memory Usage: Since each element requires additional space to store a pointer to the next element, linked lists may use more memory compared to arrays.
476
- * 4. Frequent Enqueuing and Dequeuing Operations: If your application involves frequent enqueuing and dequeuing operations and is less concerned with random access, then LinkedListQueue is a good choice.
518
+ * Queue implemented over a singly linked list; preserves head/tail operations with linear scans for queries.
519
+ * @remarks Time O(1), Space O(1)
520
+ * @template E
521
+ * @template R
522
+ * @example examples will be generated by unit test
477
523
  */
478
524
  export class LinkedListQueue<E = any, R = any> extends SinglyLinkedList<E, R> {
479
525
  /**
480
- * Time Complexity: O(n)
481
- * Space Complexity: O(n)
482
- * The `clone` function returns a new instance of the `LinkedListQueue` class with the same values as
483
- * the current instance.
484
- * @returns The `clone()` method is returning a new instance of `LinkedListQueue` with the same
485
- * values as the original `LinkedListQueue`.
526
+ * Deep clone this linked-list-based queue.
527
+ * @remarks Time O(N), Space O(N)
528
+ * @returns A new queue with the same sequence of elements.
486
529
  */
530
+
487
531
  override clone(): this {
488
- return new LinkedListQueue<E, R>(this, { toElementFn: this.toElementFn, maxLen: this._maxLen }) as this;
532
+ const out = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
533
+ for (const v of this) out.push(v);
534
+ return out;
489
535
  }
490
536
  }