min-heap-typed 1.45.3 → 1.46.2

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.
@@ -5,74 +5,313 @@
5
5
  * @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
6
6
  * @license MIT License
7
7
  */
8
- import { DoublyLinkedList } from '../linked-list';
9
8
 
10
- // O(n) time complexity of obtaining the value
11
- // O(1) time complexity of adding at the beginning and the end
12
- export class Deque<E = any> extends DoublyLinkedList<E> {
13
- }
14
9
 
15
- // O(1) time complexity of obtaining the value
16
- // O(n) time complexity of adding at the beginning and the end
17
- // todo tested slowest one
18
- export class ObjectDeque<E = number> {
19
- constructor(capacity?: number) {
20
- if (capacity !== undefined) this._capacity = capacity;
10
+ import { IterableWithSizeOrLength, IterateDirection } from "../../types";
11
+ import { calcMinUnitsRequired, rangeCheck, throwRangeError } from "../../utils";
12
+
13
+ /**
14
+ * Deque can provide random access with O(1) time complexity
15
+ * Deque is usually more compact and efficient in memory usage because it does not require additional space to store pointers.
16
+ * Deque may experience performance jitter, but DoublyLinkedList will not
17
+ * Deque is implemented using a dynamic array. Inserting or deleting beyond both ends of the array may require moving elements or reallocating space.
18
+ */
19
+
20
+ export class DequeIterator<E> {
21
+ iterateDirection: IterateDirection;
22
+
23
+ index: number;
24
+ readonly deque: Deque<E>;
25
+
26
+ /**
27
+ * The constructor initializes the index, iterate direction, and prev/next functions for a
28
+ * DequeIterator object.
29
+ * @param {number} index - The index parameter represents the current index position of the iterator
30
+ * within the deque. It is a number that indicates the position of the element that the iterator is
31
+ * currently pointing to.
32
+ * @param deque - The `deque` parameter is an instance of the `Deque` class. It represents a
33
+ * double-ended queue data structure, which allows elements to be added or removed from both ends.
34
+ * @param iterateDirection - The `iterateDirection` parameter is an optional parameter that specifies
35
+ * the direction in which the iterator should iterate over the elements of the `deque`. It has a
36
+ * default value of `IterateDirection.DEFAULT`.
37
+ * @returns The constructor is not returning anything. It is used to initialize the properties of the
38
+ * object being created.
39
+ */
40
+ constructor(index: number, deque: Deque<E>, iterateDirection = IterateDirection.DEFAULT) {
41
+ this.index = index;
42
+ this.iterateDirection = iterateDirection;
43
+ if (this.iterateDirection === IterateDirection.DEFAULT) {
44
+ this.prev = function () {
45
+ if (this.index === 0) {
46
+ throwRangeError();
47
+ }
48
+ this.index -= 1;
49
+ return this;
50
+ };
51
+ this.next = function () {
52
+ if (this.index === this.deque.size) {
53
+ throwRangeError();
54
+ }
55
+ this.index += 1;
56
+ return this;
57
+ };
58
+ } else {
59
+ this.prev = function () {
60
+ if (this.index === this.deque.size - 1) {
61
+ throwRangeError();
62
+ }
63
+ this.index += 1;
64
+ return this;
65
+ };
66
+ this.next = function () {
67
+ if (this.index === -1) {
68
+ throwRangeError();
69
+ }
70
+ this.index -= 1;
71
+ return this;
72
+ };
73
+ }
74
+ this.deque = deque;
21
75
  }
22
76
 
23
- protected _nodes: { [key: number]: E } = {};
77
+ get current() {
78
+ return this.deque.getAt(this.index);
79
+ }
24
80
 
25
- get nodes(): { [p: number]: E } {
26
- return this._nodes;
81
+ set current(newElement: E) {
82
+ this.deque.setAt(this.index, newElement);
27
83
  }
28
84
 
29
- protected _capacity = Number.MAX_SAFE_INTEGER;
85
+ isAccessible() {
86
+ return this.index !== this.deque.size;
87
+ }
30
88
 
31
- get capacity(): number {
32
- return this._capacity;
89
+ prev(): DequeIterator<E> {
90
+ return this;
33
91
  }
34
92
 
35
- protected _first = -1;
93
+ next(): DequeIterator<E> {
94
+ return this;
95
+ }
36
96
 
37
- get first(): number {
38
- return this._first;
97
+ clone() {
98
+ return new DequeIterator<E>(this.index, this.deque, this.iterateDirection);
39
99
  }
40
100
 
41
- protected _last = -1;
101
+ }
42
102
 
43
- get last(): number {
44
- return this._last;
103
+ export class Deque<E> {
104
+ protected _bucketFirst = 0;
105
+ protected _firstInBucket = 0;
106
+ protected _bucketLast = 0;
107
+ protected _lastInBucket = 0;
108
+ protected _bucketCount = 0;
109
+ protected readonly _bucketSize: number;
110
+
111
+ /**
112
+ * The constructor initializes a data structure with a specified bucket size and populates it with
113
+ * elements from an iterable.
114
+ * @param elements - The `elements` parameter is an iterable object (such as an array or a Set) that
115
+ * contains the initial elements to be stored in the data structure. It can also be an object with a
116
+ * `length` property or a `size` property, which represents the number of elements in the iterable.
117
+ * @param bucketSize - The `bucketSize` parameter is the maximum number of elements that can be
118
+ * stored in each bucket. It determines the size of each bucket in the data structure.
119
+ */
120
+ constructor(elements: IterableWithSizeOrLength<E> = [], bucketSize = (1 << 12)) {
121
+
122
+ let _size: number;
123
+ if ('length' in elements) {
124
+ if (elements.length instanceof Function) _size = elements.length(); else _size = elements.length;
125
+ } else {
126
+ if (elements.size instanceof Function) _size = elements.size();else _size = elements.size;
127
+ }
128
+
129
+ this._bucketSize = bucketSize;
130
+ this._bucketCount = calcMinUnitsRequired(_size, this._bucketSize) || 1;
131
+ for (let i = 0; i < this._bucketCount; ++i) {
132
+ this._buckets.push(new Array(this._bucketSize));
133
+ }
134
+ const needBucketNum = calcMinUnitsRequired(_size, this._bucketSize);
135
+ this._bucketFirst = this._bucketLast = (this._bucketCount >> 1) - (needBucketNum >> 1);
136
+ this._firstInBucket = this._lastInBucket = (this._bucketSize - _size % this._bucketSize) >> 1;
137
+
138
+ for (const element of elements) {
139
+ this.push(element);
140
+ }
141
+ }
142
+
143
+ protected _buckets: E[][] = [];
144
+
145
+ get buckets() {
146
+ return this._buckets;
45
147
  }
46
148
 
47
149
  protected _size = 0;
48
150
 
49
- get size(): number {
151
+ get size() {
50
152
  return this._size;
51
153
  }
52
154
 
53
155
  /**
54
- * Time Complexity: O(1)
55
- * Space Complexity: O(1)
156
+ * The function returns the first element in a collection if it exists, otherwise it returns
157
+ * undefined.
158
+ * @returns The first element of the collection, of type E, is being returned.
159
+ */
160
+ get first(): E | undefined {
161
+ if (this.size === 0) return;
162
+ return this._buckets[this._bucketFirst][this._firstInBucket];
163
+ }
164
+
165
+ get last(): E | undefined {
166
+ if (this.size === 0) return;
167
+ return this._buckets[this._bucketLast][this._lastInBucket];
168
+ }
169
+
170
+ /**
171
+ * Time Complexity: O(1) - Removes the last element.
172
+ * Space Complexity: O(1) - Operates in-place.
173
+ */
174
+
175
+ isEmpty() {
176
+ return this.size === 0;
177
+ }
178
+
179
+ /**
180
+ * Time Complexity: Amortized O(1) - Similar to push, resizing leads to O(n).
181
+ * Space Complexity: O(n) - Due to potential resizing.
56
182
  */
57
183
 
58
184
  /**
59
185
  * Time Complexity: O(1)
60
- * Space Complexity: O(1)
186
+ * Space Complexity: O(n) - In worst case, resizing doubles the array size.
61
187
  *
62
- * The "addFirst" function adds a value to the beginning of an array-like data structure.
63
- * @param {E} value - The `value` parameter represents the value that you want to add to the beginning of the data
188
+ * The addLast function adds an element to the end of an array.
189
+ * @param {E} element - The element parameter represents the element that you want to add to the end of the
190
+ * data structure.
191
+ */
192
+ addLast(element: E): void {
193
+ this.push(element);
194
+ }
195
+
196
+ /**
197
+ * Time Complexity: O(1) - Removes the first element.
198
+ * Space Complexity: O(1) - In-place operation.
199
+ */
200
+
201
+ /**
202
+ * Time Complexity: O(1) - Removes the last element.
203
+ * Space Complexity: O(1) - Operates in-place.
204
+ *
205
+ * The function "popLast" removes and returns the last element of an array.
206
+ * @returns The last element of the array is being returned.
207
+ */
208
+ popLast(): E | undefined {
209
+ return this.pop();
210
+ }
211
+
212
+ /**
213
+ * Time Complexity: O(1).
214
+ * Space Complexity: O(n) - Due to potential resizing.
215
+ *
216
+ * The "addFirst" function adds an element to the beginning of an array.
217
+ * @param {E} element - The parameter "element" represents the element that you want to add to the
218
+ * beginning of the data structure.
219
+ */
220
+ addFirst(element: E): void {
221
+ this.unshift(element);
222
+ }
223
+
224
+ /**
225
+ * Time Complexity: O(1) - Removes the first element.
226
+ * Space Complexity: O(1) - In-place operation.
227
+ *
228
+ * The function "popFirst" removes and returns the first element of an array.
229
+ * @returns The method `popFirst()` is returning the first element of the array after removing it
230
+ * from the beginning. If the array is empty, it will return `undefined`.
231
+ */
232
+ popFirst(): E | undefined {
233
+ return this.shift();
234
+ }
235
+
236
+ /**
237
+ * The clear() function resets the state of the object by initializing all variables to their default
238
+ * values.
239
+ */
240
+ clear() {
241
+ this._buckets = [new Array(this._bucketSize)];
242
+ this._bucketCount = 1;
243
+ this._bucketFirst = this._bucketLast = this._size = 0;
244
+ this._firstInBucket = this._lastInBucket = this._bucketSize >> 1;
245
+ }
246
+
247
+ /**
248
+ * The `begin()` function returns a new iterator for a deque starting from the first element.
249
+ * @returns A new instance of the DequeIterator class is being returned.
250
+ */
251
+ begin() {
252
+ return new DequeIterator<E>(0, this);
253
+ }
254
+
255
+ /**
256
+ * The `end()` function returns a new `DequeIterator` object with the size and reference to the
257
+ * current deque.
258
+ * @returns A new instance of the DequeIterator class is being returned.
259
+ */
260
+ end() {
261
+ return new DequeIterator<E>(this.size, this);
262
+ }
263
+
264
+ /**
265
+ * The reverseBegin function returns a new DequeIterator object that starts at the last element of
266
+ * the deque and iterates in reverse direction.
267
+ * @returns A new instance of the DequeIterator class is being returned.
268
+ */
269
+ reverseBegin() {
270
+ return new DequeIterator<E>(this.size - 1, this, IterateDirection.REVERSE);
271
+ }
272
+
273
+ /**
274
+ * The reverseEnd() function returns a new DequeIterator object that iterates over the elements of a
275
+ * Deque in reverse order.
276
+ * @returns A new instance of the DequeIterator class is being returned.
277
+ */
278
+ reverseEnd() {
279
+ return new DequeIterator<E>(-1, this, IterateDirection.REVERSE);
280
+ }
281
+
282
+ /**
283
+ * Time Complexity - Amortized O(1) (possible reallocation)
284
+ * Space Complexity - O(n) (due to potential resizing).
285
+ */
286
+
287
+ /**
288
+ * Time Complexity - Amortized O(1) (possible reallocation),
289
+ * Space Complexity - O(n) (due to potential resizing).
290
+ *
291
+ * The push function adds an element to a data structure and reallocates memory if necessary.
292
+ * @param {E} element - The `element` parameter represents the value that you want to add to the data
64
293
  * structure.
294
+ * @returns The size of the data structure after the element has been pushed.
65
295
  */
66
- addFirst(value: E) {
67
- if (this.size === 0) {
68
- const mid = Math.floor(this.capacity / 2);
69
- this._first = mid;
70
- this._last = mid;
71
- } else {
72
- this._first--;
296
+ push(element: E) {
297
+ if (this.size) {
298
+ if (this._lastInBucket < this._bucketSize - 1) {
299
+ this._lastInBucket += 1;
300
+ } else if (this._bucketLast < this._bucketCount - 1) {
301
+ this._bucketLast += 1;
302
+ this._lastInBucket = 0;
303
+ } else {
304
+ this._bucketLast = 0;
305
+ this._lastInBucket = 0;
306
+ }
307
+ if (
308
+ this._bucketLast === this._bucketFirst &&
309
+ this._lastInBucket === this._firstInBucket
310
+ ) this._reallocate();
73
311
  }
74
- this.nodes[this.first] = value;
75
- this._size++;
312
+ this._size += 1;
313
+ this._buckets[this._bucketLast][this._lastInBucket] = element;
314
+ return this.size;
76
315
  }
77
316
 
78
317
  /**
@@ -84,21 +323,65 @@ export class ObjectDeque<E = number> {
84
323
  * Time Complexity: O(1)
85
324
  * Space Complexity: O(1)
86
325
  *
87
- * The addLast function adds a value to the end of an array-like data structure.
88
- * @param {E} value - The `value` parameter represents the value that you want to add to the end of the data structure.
326
+ * The `pop()` function removes and returns the last element from a data structure, updating the
327
+ * internal state variables accordingly.
328
+ * @returns The element that was removed from the data structure is being returned.
89
329
  */
90
- addLast(value: E) {
91
- if (this.size === 0) {
92
- const mid = Math.floor(this.capacity / 2);
93
- this._first = mid;
94
- this._last = mid;
95
- } else {
96
- this._last++;
330
+ pop() {
331
+ if (this.size === 0) return;
332
+ const element = this._buckets[this._bucketLast][this._lastInBucket];
333
+ if (this.size !== 1) {
334
+ if (this._lastInBucket > 0) {
335
+ this._lastInBucket -= 1;
336
+ } else if (this._bucketLast > 0) {
337
+ this._bucketLast -= 1;
338
+ this._lastInBucket = this._bucketSize - 1;
339
+ } else {
340
+ this._bucketLast = this._bucketCount - 1;
341
+ this._lastInBucket = this._bucketSize - 1;
342
+ }
97
343
  }
98
- this.nodes[this.last] = value;
99
- this._size++;
344
+ this._size -= 1;
345
+ return element;
100
346
  }
101
347
 
348
+ /**
349
+ * Time Complexity: Amortized O(1)
350
+ * Space Complexity: O(n)
351
+ */
352
+
353
+ /**
354
+ * Time Complexity: Amortized O(1)
355
+ * Space Complexity: O(n)
356
+ *
357
+ * The `unshift` function adds an element to the beginning of an array-like data structure and
358
+ * returns the new size of the structure.
359
+ * @param {E} element - The `element` parameter represents the element that you want to add to the
360
+ * beginning of the data structure.
361
+ * @returns The size of the data structure after the element has been added.
362
+ */
363
+ unshift(element: E) {
364
+ if (this.size) {
365
+ if (this._firstInBucket > 0) {
366
+ this._firstInBucket -= 1;
367
+ } else if (this._bucketFirst > 0) {
368
+ this._bucketFirst -= 1;
369
+ this._firstInBucket = this._bucketSize - 1;
370
+ } else {
371
+ this._bucketFirst = this._bucketCount - 1;
372
+ this._firstInBucket = this._bucketSize - 1;
373
+ }
374
+ if (
375
+ this._bucketFirst === this._bucketLast &&
376
+ this._firstInBucket === this._lastInBucket
377
+ ) this._reallocate();
378
+ }
379
+ this._size += 1;
380
+ this._buckets[this._bucketFirst][this._firstInBucket] = element;
381
+ return this.size;
382
+ }
383
+
384
+
102
385
  /**
103
386
  * Time Complexity: O(1)
104
387
  * Space Complexity: O(1)
@@ -108,18 +391,30 @@ export class ObjectDeque<E = number> {
108
391
  * Time Complexity: O(1)
109
392
  * Space Complexity: O(1)
110
393
  *
111
- * The function `popFirst()` removes and returns the first element in a data structure.
112
- * @returns The value of the first element in the data structure.
394
+ * The `shift()` function removes and returns the first element from a data structure, updating the
395
+ * internal state variables accordingly.
396
+ * @returns The element that is being removed from the beginning of the data structure is being
397
+ * returned.
113
398
  */
114
- popFirst() {
115
- if (!this.size) return;
116
- const value = this.getFirst();
117
- delete this.nodes[this.first];
118
- this._first++;
119
- this._size--;
120
- return value;
399
+ shift() {
400
+ if (this.size === 0) return;
401
+ const element = this._buckets[this._bucketFirst][this._firstInBucket];
402
+ if (this.size !== 1) {
403
+ if (this._firstInBucket < this._bucketSize - 1) {
404
+ this._firstInBucket += 1;
405
+ } else if (this._bucketFirst < this._bucketCount - 1) {
406
+ this._bucketFirst += 1;
407
+ this._firstInBucket = 0;
408
+ } else {
409
+ this._bucketFirst = 0;
410
+ this._firstInBucket = 0;
411
+ }
412
+ }
413
+ this._size -= 1;
414
+ return element;
121
415
  }
122
416
 
417
+
123
418
  /**
124
419
  * Time Complexity: O(1)
125
420
  * Space Complexity: O(1)
@@ -129,13 +424,22 @@ export class ObjectDeque<E = number> {
129
424
  * Time Complexity: O(1)
130
425
  * Space Complexity: O(1)
131
426
  *
132
- * The `getFirst` function returns the first element in an array-like data structure if it exists.
133
- * @returns The element at the first position of the `_nodes` array.
427
+ * The `getAt` function retrieves an element at a specified position in an array-like data structure.
428
+ * @param {number} pos - The `pos` parameter represents the position of the element that you want to
429
+ * retrieve from the data structure. It is of type `number` and should be a valid index within the
430
+ * range of the data structure.
431
+ * @returns The element at the specified position in the data structure is being returned.
134
432
  */
135
- getFirst() {
136
- if (this.size) return this.nodes[this.first];
433
+ getAt(pos: number): E {
434
+ rangeCheck!(pos, 0, this.size - 1);
435
+ const {
436
+ bucketIndex,
437
+ indexInBucket
438
+ } = this._getBucketAndPosition(pos);
439
+ return this._buckets[bucketIndex][indexInBucket]!;
137
440
  }
138
441
 
442
+
139
443
  /**
140
444
  * Time Complexity: O(1)
141
445
  * Space Complexity: O(1)
@@ -145,17 +449,58 @@ export class ObjectDeque<E = number> {
145
449
  * Time Complexity: O(1)
146
450
  * Space Complexity: O(1)
147
451
  *
148
- * The `popLast()` function removes and returns the last element in a data structure.
149
- * @returns The value that was removed from the data structure.
452
+ * The `setAt` function sets an element at a specific position in an array-like data structure.
453
+ * @param {number} pos - The `pos` parameter represents the position at which the element needs to be
454
+ * set. It is of type `number`.
455
+ * @param {E} element - The `element` parameter is the value that you want to set at the specified
456
+ * position in the data structure.
150
457
  */
151
- popLast() {
152
- if (!this.size) return;
153
- const value = this.getLast();
154
- delete this.nodes[this.last];
155
- this._last--;
156
- this._size--;
458
+ setAt(pos: number, element: E) {
459
+ rangeCheck!(pos, 0, this.size - 1);
460
+ const {
461
+ bucketIndex,
462
+ indexInBucket
463
+ } = this._getBucketAndPosition(pos);
464
+ this._buckets[bucketIndex][indexInBucket] = element;
465
+ }
157
466
 
158
- return value;
467
+ /**
468
+ * Time Complexity: O(n)
469
+ * Space Complexity: O(n)
470
+ */
471
+
472
+ /**
473
+ * Time Complexity: O(n)
474
+ * Space Complexity: O(n)
475
+ *
476
+ * The `insertAt` function inserts one or more elements at a specified position in an array-like data
477
+ * structure.
478
+ * @param {number} pos - The `pos` parameter represents the position at which the element(s) should
479
+ * be inserted. It is of type `number`.
480
+ * @param {E} element - The `element` parameter represents the element that you want to insert into
481
+ * the array at the specified position.
482
+ * @param [num=1] - The `num` parameter represents the number of times the `element` should be
483
+ * inserted at the specified position (`pos`). By default, it is set to 1, meaning that the `element`
484
+ * will be inserted once. However, you can provide a different value for `num` if you want
485
+ * @returns The size of the array after the insertion is being returned.
486
+ */
487
+ insertAt(pos: number, element: E, num = 1) {
488
+ const length = this.size;
489
+ rangeCheck!(pos, 0, length);
490
+ if (pos === 0) {
491
+ while (num--) this.unshift(element);
492
+ } else if (pos === this.size) {
493
+ while (num--) this.push(element);
494
+ } else {
495
+ const arr: E[] = [];
496
+ for (let i = pos; i < this.size; ++i) {
497
+ arr.push(this.getAt(i));
498
+ }
499
+ this.cut(pos - 1);
500
+ for (let i = 0; i < num; ++i) this.push(element);
501
+ for (let i = 0; i < arr.length; ++i) this.push(arr[i]);
502
+ }
503
+ return this.size;
159
504
  }
160
505
 
161
506
  /**
@@ -167,85 +512,279 @@ export class ObjectDeque<E = number> {
167
512
  * Time Complexity: O(1)
168
513
  * Space Complexity: O(1)
169
514
  *
170
- * The `getLast()` function returns the last element in an array-like data structure.
171
- * @returns The last element in the array "_nodes" is being returned.
515
+ * The `cut` function updates the state of the object based on the given position and returns the
516
+ * updated size.
517
+ * @param {number} pos - The `pos` parameter represents the position at which the string should be
518
+ * cut. It is a number that indicates the index of the character where the cut should be made.
519
+ * @returns The method is returning the updated size of the data structure.
172
520
  */
173
- getLast() {
174
- if (this.size) return this.nodes[this.last];
521
+ cut(pos: number) {
522
+ if (pos < 0) {
523
+ this.clear();
524
+ return 0;
525
+ }
526
+ const {
527
+ bucketIndex,
528
+ indexInBucket
529
+ } = this._getBucketAndPosition(pos);
530
+ this._bucketLast = bucketIndex;
531
+ this._lastInBucket = indexInBucket;
532
+ this._size = pos + 1;
533
+ return this.size;
175
534
  }
176
535
 
177
536
  /**
178
- * Time Complexity: O(1)
537
+ * Time Complexity: O(n)
179
538
  * Space Complexity: O(1)
180
539
  */
181
540
 
182
541
  /**
183
- * Time Complexity: O(1)
542
+ * Time Complexity: O(n)
184
543
  * Space Complexity: O(1)
185
544
  *
186
- * The get function returns the element at the specified index in an array-like data structure.
187
- * @param {number} index - The index parameter is a number that represents the position of the element you want to
188
- * retrieve from the array.
189
- * @returns The element at the specified index in the `_nodes` array is being returned. If there is no element at that
190
- * index, `null` is returned.
545
+ * The `deleteAt` function removes an element at a specified position in an array-like data
546
+ * structure.
547
+ * @param {number} pos - The `pos` parameter in the `deleteAt` function represents the position at
548
+ * which an element needs to be deleted from the data structure. It is of type `number` and indicates
549
+ * the index of the element to be deleted.
550
+ * @returns The size of the data structure after the deletion operation is performed.
191
551
  */
192
- get(index: number) {
193
- return this.nodes[this.first + index] || null;
552
+ deleteAt(pos: number) {
553
+ rangeCheck!(pos, 0, this.size - 1);
554
+ if (pos === 0) this.shift();
555
+ else if (pos === this.size - 1) this.pop();
556
+ else {
557
+ const length = this.size - 1;
558
+ let {
559
+ bucketIndex: curBucket,
560
+ indexInBucket: curPointer
561
+ } = this._getBucketAndPosition(pos);
562
+ for (let i = pos; i < length; ++i) {
563
+ const {
564
+ bucketIndex: nextBucket,
565
+ indexInBucket: nextPointer
566
+ } = this._getBucketAndPosition(pos + 1);
567
+ this._buckets[curBucket][curPointer] = this._buckets[nextBucket][nextPointer];
568
+ curBucket = nextBucket;
569
+ curPointer = nextPointer;
570
+ }
571
+ this.pop();
572
+ }
573
+ return this.size;
194
574
  }
195
575
 
196
576
  /**
197
- * The function checks if the size of a data structure is less than or equal to zero.
198
- * @returns The method is returning a boolean value indicating whether the size of the object is less than or equal to 0.
577
+ * Time Complexity: O(n)
578
+ * Space Complexity: O(1)
199
579
  */
200
- isEmpty() {
201
- return this.size <= 0;
580
+
581
+ /**
582
+ * Time Complexity: O(n)
583
+ * Space Complexity: O(1)
584
+ *
585
+ * The `delete` function removes all occurrences of a specified element from an array-like data
586
+ * structure.
587
+ * @param {E} element - The `element` parameter represents the element that you want to delete from
588
+ * the data structure.
589
+ * @returns The size of the data structure after the element has been deleted.
590
+ */
591
+ delete(element: E) {
592
+ const size = this.size;
593
+ if (size === 0) return 0;
594
+ let i = 0;
595
+ let index = 0;
596
+ while (i < size) {
597
+ const oldElement = this.getAt(i);
598
+ if (oldElement !== element) {
599
+ this.setAt(index, oldElement!);
600
+ index += 1;
601
+ }
602
+ i += 1;
603
+ }
604
+ this.cut(index - 1);
605
+ return this.size;
202
606
  }
203
- }
204
607
 
205
- // O(1) time complexity of obtaining the value
206
- // O(n) time complexity of adding at the beginning and the end
207
- export class ArrayDeque<E> {
208
- protected _nodes: E[] = [];
608
+ /**
609
+ * Time Complexity: O(n)
610
+ * Space Complexity: O(1)
611
+ */
209
612
 
210
- get nodes(): E[] {
211
- return this._nodes;
613
+ /**
614
+ * Time Complexity: O(n)
615
+ * Space Complexity: O(1)
616
+ *
617
+ * The function deletes an element from a deque using an iterator and returns the next iterator.
618
+ * @param iter - The parameter `iter` is of type `DequeIterator<E>`. It represents an iterator object
619
+ * that is used to iterate over elements in a deque (double-ended queue).
620
+ * @returns the updated iterator after deleting an element from the deque.
621
+ */
622
+ deleteByIterator(iter: DequeIterator<E>) {
623
+ const index = iter.index;
624
+ this.deleteAt(index);
625
+ iter = iter.next();
626
+ return iter;
212
627
  }
213
628
 
214
- get size() {
215
- return this.nodes.length;
629
+ /**
630
+ * Time Complexity: O(n)
631
+ * Space Complexity: O(1)
632
+ */
633
+
634
+ /**
635
+ * Time Complexity: O(n)
636
+ * Space Complexity: O(1)
637
+ *
638
+ * The function `findIterator` searches for an element in a deque and returns an iterator pointing to
639
+ * the element if found, otherwise it returns an iterator pointing to the end of the deque.
640
+ * @param {E} element - The `element` parameter is the element that you want to find in the deque.
641
+ * @returns The method `findIterator(element: E)` returns a `DequeIterator<E>` object.
642
+ */
643
+ findIterator(element: E) {
644
+ for (let i = 0; i < this.size; ++i) {
645
+ if (this.getAt(i) === element) {
646
+ return new DequeIterator<E>(i, this);
647
+ }
648
+ }
649
+ return this.end();
216
650
  }
217
651
 
218
652
  /**
219
- * Time Complexity: O(1)
653
+ * Time Complexity: O(n)
220
654
  * Space Complexity: O(1)
221
655
  */
222
656
 
223
657
  /**
224
- * Time Complexity: O(1)
658
+ * Time Complexity: O(n)
225
659
  * Space Complexity: O(1)
226
660
  *
227
- * The function "addLast" adds a value to the end of an array.
228
- * @param {E} value - The value parameter represents the value that you want to add to the end of the array.
229
- * @returns The return value is the new length of the array after the value has been added.
661
+ * The reverse() function reverses the order of the buckets and the elements within each bucket in a
662
+ * data structure.
663
+ * @returns The reverse() method is returning the object itself (this) after performing the reverse
664
+ * operation on the buckets and updating the relevant properties.
230
665
  */
231
- addLast(value: E) {
232
- return this.nodes.push(value);
666
+ reverse() {
667
+ this._buckets.reverse().forEach(function (bucket) {
668
+ bucket.reverse();
669
+ });
670
+ const { _bucketFirst, _bucketLast, _firstInBucket, _lastInBucket } = this;
671
+ this._bucketFirst = this._bucketCount - _bucketLast - 1;
672
+ this._bucketLast = this._bucketCount - _bucketFirst - 1;
673
+ this._firstInBucket = this._bucketSize - _lastInBucket - 1;
674
+ this._lastInBucket = this._bucketSize - _firstInBucket - 1;
675
+ return this;
233
676
  }
234
677
 
235
678
  /**
236
- * Time Complexity: O(1)
679
+ * Time Complexity: O(n)
237
680
  * Space Complexity: O(1)
238
681
  */
239
682
 
240
683
  /**
241
- * Time Complexity: O(1)
684
+ * Time Complexity: O(n)
685
+ * Space Complexity: O(1)
686
+ *
687
+ * The `unique()` function removes duplicate elements from an array-like data structure and returns
688
+ * the number of unique elements.
689
+ * @returns The size of the modified array is being returned.
690
+ */
691
+ unique() {
692
+ if (this.size <= 1) {
693
+ return this.size;
694
+ }
695
+ let index = 1;
696
+ let prev = this.getAt(0);
697
+ for (let i = 1; i < this.size; ++i) {
698
+ const cur = this.getAt(i);
699
+ if (cur !== prev) {
700
+ prev = cur;
701
+ this.setAt(index++, cur);
702
+ }
703
+ }
704
+ this.cut(index - 1);
705
+ return this.size;
706
+ }
707
+
708
+ /**
709
+ * Time Complexity: O(n log n)
710
+ * Space Complexity: O(n)
711
+ */
712
+
713
+ /**
714
+ * Time Complexity: O(n log n)
715
+ * Space Complexity: O(n)
716
+ *
717
+ * The `sort` function sorts the elements in a data structure using a provided comparator function.
718
+ * @param [comparator] - The `comparator` parameter is a function that takes in two elements `x` and
719
+ * `y` of type `E` and returns a number. The comparator function is used to determine the order of
720
+ * the elements in the sorted array.
721
+ * @returns The method is returning the sorted instance of the object on which the method is called.
722
+ */
723
+ sort(comparator?: (x: E, y: E) => number) {
724
+ const arr: E[] = [];
725
+ for (let i = 0; i < this.size; ++i) {
726
+ arr.push(this.getAt(i));
727
+ }
728
+ arr.sort(comparator);
729
+ for (let i = 0; i < this.size; ++i) {
730
+ this.setAt(i, arr[i]);
731
+ }
732
+ return this;
733
+ }
734
+
735
+ /**
736
+ * Time Complexity: O(n)
737
+ * Space Complexity: O(n)
738
+ */
739
+
740
+ /**
741
+ * Time Complexity: O(n)
742
+ * Space Complexity: O(n)
743
+ *
744
+ * The `shrinkToFit` function reorganizes the elements in an array-like data structure to minimize
745
+ * memory usage.
746
+ * @returns Nothing is being returned. The function is using the `return` statement to exit early if
747
+ * `this.size` is 0, but it does not return any value.
748
+ */
749
+ shrinkToFit() {
750
+ if (this.size === 0) return;
751
+ const newBuckets = [];
752
+ if (this._bucketFirst === this._bucketLast) return;
753
+ else if (this._bucketFirst < this._bucketLast) {
754
+ for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
755
+ newBuckets.push(this._buckets[i]);
756
+ }
757
+ } else {
758
+ for (let i = this._bucketFirst; i < this._bucketCount; ++i) {
759
+ newBuckets.push(this._buckets[i]);
760
+ }
761
+ for (let i = 0; i <= this._bucketLast; ++i) {
762
+ newBuckets.push(this._buckets[i]);
763
+ }
764
+ }
765
+ this._bucketFirst = 0;
766
+ this._bucketLast = newBuckets.length - 1;
767
+ this._buckets = newBuckets;
768
+ }
769
+
770
+ /**
771
+ * Time Complexity: O(n)
772
+ * Space Complexity: O(1)
773
+ */
774
+
775
+ /**
776
+ * Time Complexity: O(n)
242
777
  * Space Complexity: O(1)
243
778
  *
244
- * The function "popLast" returns and removes the last element from an array, or returns null if the array is empty.
245
- * @returns The method `popLast()` returns the last element of the `_nodes` array, or `null` if the array is empty.
779
+ * The `forEach` function iterates over each element in a deque and applies a callback function to
780
+ * each element.
781
+ * @param callback - The callback parameter is a function that will be called for each element in the
782
+ * deque. It takes three parameters:
246
783
  */
247
- popLast(): E | null {
248
- return this.nodes.pop() ?? null;
784
+ forEach(callback: (element: E, index: number, deque: Deque<E>) => void) {
785
+ for (let i = 0; i < this.size; ++i) {
786
+ callback(this.getAt(i), i, this);
787
+ }
249
788
  }
250
789
 
251
790
  /**
@@ -257,12 +796,90 @@ export class ArrayDeque<E> {
257
796
  * Time Complexity: O(n)
258
797
  * Space Complexity: O(1)
259
798
  *
260
- * The `popFirst` function removes and returns the first element from an array, or returns null if the array is empty.
261
- * @returns The `popFirst()` function returns the first element of the `_nodes` array, or `null` if the array is
262
- * empty.
799
+ * The `find` function iterates over the elements in a deque and returns the first element for which
800
+ * the callback function returns true, or undefined if no such element is found.
801
+ * @param callback - A function that takes three parameters: element, index, and deque. It should
802
+ * return a boolean value indicating whether the element satisfies a certain condition.
803
+ * @returns The method `find` returns the first element in the deque that satisfies the condition
804
+ * specified by the callback function. If no element satisfies the condition, it returns `undefined`.
263
805
  */
264
- popFirst(): E | null {
265
- return this.nodes.shift() ?? null;
806
+ find(callback: (element: E, index: number, deque: Deque<E>) => boolean): E | undefined {
807
+ for (let i = 0; i < this.size; ++i) {
808
+ const element = this.getAt(i);
809
+ if (callback(element, i, this)) {
810
+ return element;
811
+ }
812
+ }
813
+ return undefined;
814
+ }
815
+
816
+ /**
817
+ * Time Complexity: O(n)
818
+ * Space Complexity: O(n)
819
+ */
820
+
821
+ /**
822
+ * Time Complexity: O(n)
823
+ * Space Complexity: O(n)
824
+ *
825
+ * The `toArray` function converts the elements of a data structure into an array.
826
+ * @returns The `toArray()` method is returning an array of elements of type `E`.
827
+ */
828
+ toArray(): E[] {
829
+ const arr: E[] = [];
830
+ for (let i = 0; i < this.size; ++i) {
831
+ arr.push(this.getAt(i));
832
+ }
833
+ return arr;
834
+ }
835
+
836
+ /**
837
+ * Time Complexity: O(n)
838
+ * Space Complexity: O(n)
839
+ */
840
+
841
+ /**
842
+ * Time Complexity: O(n)
843
+ * Space Complexity: O(n)
844
+ *
845
+ * The `map` function takes a callback function and applies it to each element in the deque,
846
+ * returning a new deque with the results.
847
+ * @param callback - The `callback` parameter is a function that takes three arguments:
848
+ * @returns The `map` method is returning a new `Deque` object with the transformed elements.
849
+ */
850
+ map<T>(callback: (element: E, index: number, deque: Deque<E>) => T): Deque<T> {
851
+ const newDeque = new Deque<T>([], this._bucketSize);
852
+ for (let i = 0; i < this.size; ++i) {
853
+ newDeque.push(callback(this.getAt(i), i, this));
854
+ }
855
+ return newDeque;
856
+ }
857
+
858
+ /**
859
+ * Time Complexity: O(n)
860
+ * Space Complexity: O(n)
861
+ */
862
+
863
+ /**
864
+ * Time Complexity: O(n)
865
+ * Space Complexity: O(n)
866
+ *
867
+ * The `filter` function creates a new deque containing only the elements that satisfy the given
868
+ * predicate function.
869
+ * @param predicate - The `predicate` parameter is a function that takes three arguments: `element`,
870
+ * `index`, and `deque`.
871
+ * @returns The `filter` method is returning a new `Deque` object that contains only the elements
872
+ * that satisfy the given `predicate` function.
873
+ */
874
+ filter(predicate: (element: E, index: number, deque: Deque<E>) => boolean): Deque<E> {
875
+ const newDeque = new Deque<E>([], this._bucketSize);
876
+ for (let i = 0; i < this.size; ++i) {
877
+ const element = this.getAt(i);
878
+ if (predicate(element, i, this)) {
879
+ newDeque.push(element);
880
+ }
881
+ }
882
+ return newDeque;
266
883
  }
267
884
 
268
885
  /**
@@ -274,13 +891,172 @@ export class ArrayDeque<E> {
274
891
  * Time Complexity: O(n)
275
892
  * Space Complexity: O(1)
276
893
  *
277
- * The function "addFirst" adds a value to the beginning of an array.
278
- * @param {E} value - The value parameter represents the value that you want to add to the beginning of the array.
279
- * @returns The return value of the `addFirst` function is the new length of the array `_nodes` after adding the
280
- * `value` at the beginning.
894
+ * The `reduce` function iterates over the elements of a deque and applies a callback function to
895
+ * each element, accumulating a single value.
896
+ * @param callback - The `callback` parameter is a function that takes four arguments:
897
+ * @param {T} initialValue - The `initialValue` parameter is the initial value of the accumulator. It
898
+ * is the value that will be passed as the first argument to the `callback` function when reducing
899
+ * the elements of the deque.
900
+ * @returns the final value of the accumulator after iterating over all elements in the deque and
901
+ * applying the callback function to each element.
902
+ */
903
+ reduce<T>(callback: (accumulator: T, element: E, index: number, deque: Deque<E>) => T, initialValue: T): T {
904
+ let accumulator = initialValue;
905
+ for (let i = 0; i < this.size; ++i) {
906
+ accumulator = callback(accumulator, this.getAt(i), i, this);
907
+ }
908
+ return accumulator;
909
+ }
910
+
911
+ /**
912
+ * Time Complexity: O(n)
913
+ * Space Complexity: O(1)
914
+ */
915
+
916
+ /**
917
+ * Time Complexity: O(n)
918
+ * Space Complexity: O(1)
919
+ *
920
+ * The function "indexOf" returns the index of the first occurrence of a given element in an array,
921
+ * or -1 if the element is not found.
922
+ * @param {E} element - The "element" parameter represents the element that you want to find the
923
+ * index of in the data structure.
924
+ * @returns The indexOf function returns the index of the first occurrence of the specified element
925
+ * in the data structure. If the element is not found, it returns -1.
926
+ */
927
+ indexOf(element: E): number {
928
+ for (let i = 0; i < this.size; ++i) {
929
+ if (this.getAt(i) === element) {
930
+ return i;
931
+ }
932
+ }
933
+ return -1;
934
+ }
935
+
936
+ /**
937
+ * Time Complexity: O(n)
938
+ * Space Complexity: O(1)
939
+ */
940
+
941
+ /**
942
+ * Time Complexity: O(n)
943
+ * Space Complexity: O(1)
944
+ *
945
+ * The above function is an implementation of the iterator protocol in TypeScript, allowing the
946
+ * object to be iterated over using a for...of loop.
947
+ */
948
+ * [Symbol.iterator]() {
949
+ for (let i = 0; i < this.size; ++i) {
950
+ yield this.getAt(i);
951
+ }
952
+ }
953
+
954
+ /**
955
+ * Time Complexity: O(n)
956
+ * Space Complexity: O(n)
957
+ */
958
+
959
+ /**
960
+ * Time Complexity: O(n)
961
+ * Space Complexity: O(n)
962
+ *
963
+ * The `_reallocate` function reallocates the buckets in an array, adding new buckets if needed.
964
+ * @param {number} [needBucketNum] - The `needBucketNum` parameter is an optional number that
965
+ * specifies the number of new buckets needed. If not provided, it will default to half of the
966
+ * current bucket count (`this._bucketCount >> 1`) or 1 if the current bucket count is less than 2.
967
+ */
968
+ protected _reallocate(needBucketNum?: number) {
969
+ const newBuckets = [];
970
+ const addBucketNum = needBucketNum || this._bucketCount >> 1 || 1;
971
+ for (let i = 0; i < addBucketNum; ++i) {
972
+ newBuckets[i] = new Array(this._bucketSize);
973
+ }
974
+ for (let i = this._bucketFirst; i < this._bucketCount; ++i) {
975
+ newBuckets[newBuckets.length] = this._buckets[i];
976
+ }
977
+ for (let i = 0; i < this._bucketLast; ++i) {
978
+ newBuckets[newBuckets.length] = this._buckets[i];
979
+ }
980
+ newBuckets[newBuckets.length] = [...this._buckets[this._bucketLast]];
981
+ this._bucketFirst = addBucketNum;
982
+ this._bucketLast = newBuckets.length - 1;
983
+ for (let i = 0; i < addBucketNum; ++i) {
984
+ newBuckets[newBuckets.length] = new Array(this._bucketSize);
985
+ }
986
+ this._buckets = newBuckets;
987
+ this._bucketCount = newBuckets.length;
988
+ }
989
+
990
+ /**
991
+ * Time Complexity: O(1)
992
+ * Space Complexity: O(1)
993
+ */
994
+
995
+ /**
996
+ * Time Complexity: O(1)
997
+ * Space Complexity: O(1)
998
+ *
999
+ * The function calculates the bucket index and index within the bucket based on the given position.
1000
+ * @param {number} pos - The `pos` parameter represents the position within the data structure. It is
1001
+ * a number that indicates the index or position of an element within the structure.
1002
+ * @returns an object with two properties: "bucketIndex" and "indexInBucket".
281
1003
  */
282
- addFirst(value: E) {
283
- return this.nodes.unshift(value);
1004
+ protected _getBucketAndPosition(pos: number) {
1005
+ let bucketIndex: number;
1006
+ let indexInBucket: number;
1007
+
1008
+ const overallIndex = this._firstInBucket + pos;
1009
+ bucketIndex = this._bucketFirst + Math.floor(overallIndex / this._bucketSize);
1010
+
1011
+ if (bucketIndex >= this._bucketCount) {
1012
+ bucketIndex -= this._bucketCount;
1013
+ }
1014
+
1015
+ indexInBucket = (overallIndex + 1) % this._bucketSize - 1;
1016
+ if (indexInBucket < 0) {
1017
+ indexInBucket = this._bucketSize - 1;
1018
+ }
1019
+
1020
+ return { bucketIndex, indexInBucket };
1021
+ }
1022
+ }
1023
+
1024
+ // O(1) time complexity of obtaining the element
1025
+ // O(n) time complexity of adding at the beginning and the end
1026
+ // todo tested slowest one
1027
+ export class ObjectDeque<E = number> {
1028
+ constructor(capacity?: number) {
1029
+ if (capacity !== undefined) this._capacity = capacity;
1030
+ }
1031
+
1032
+ protected _nodes: { [key: number]: E } = {};
1033
+
1034
+ get nodes(): { [p: number]: E } {
1035
+ return this._nodes;
1036
+ }
1037
+
1038
+ protected _capacity = Number.MAX_SAFE_INTEGER;
1039
+
1040
+ get capacity(): number {
1041
+ return this._capacity;
1042
+ }
1043
+
1044
+ protected _first = -1;
1045
+
1046
+ get first(): number {
1047
+ return this._first;
1048
+ }
1049
+
1050
+ protected _last = -1;
1051
+
1052
+ get last(): number {
1053
+ return this._last;
1054
+ }
1055
+
1056
+ protected _size = 0;
1057
+
1058
+ get size(): number {
1059
+ return this._size;
284
1060
  }
285
1061
 
286
1062
  /**
@@ -292,12 +1068,20 @@ export class ArrayDeque<E> {
292
1068
  * Time Complexity: O(1)
293
1069
  * Space Complexity: O(1)
294
1070
  *
295
- * The `getFirst` function returns the first element of an array or null if the array is empty.
296
- * @returns The function `getFirst()` is returning the first element (`E`) of the `_nodes` array. If the array is
297
- * empty, it will return `null`.
1071
+ * The "addFirst" function adds an element to the beginning of an array-like data structure.
1072
+ * @param {E} element - The `element` parameter represents the element that you want to add to the beginning of the data
1073
+ * structure.
298
1074
  */
299
- getFirst(): E | null {
300
- return this.nodes[0] ?? null;
1075
+ addFirst(element: E) {
1076
+ if (this.size === 0) {
1077
+ const mid = Math.floor(this.capacity / 2);
1078
+ this._first = mid;
1079
+ this._last = mid;
1080
+ } else {
1081
+ this._first--;
1082
+ }
1083
+ this.nodes[this.first] = element;
1084
+ this._size++;
301
1085
  }
302
1086
 
303
1087
  /**
@@ -309,11 +1093,19 @@ export class ArrayDeque<E> {
309
1093
  * Time Complexity: O(1)
310
1094
  * Space Complexity: O(1)
311
1095
  *
312
- * The `getLast` function returns the last element of an array or null if the array is empty.
313
- * @returns The method `getLast()` returns the last element of the `_nodes` array, or `null` if the array is empty.
1096
+ * The addLast function adds an element to the end of an array-like data structure.
1097
+ * @param {E} element - The `element` parameter represents the element that you want to add to the end of the data structure.
314
1098
  */
315
- getLast(): E | null {
316
- return this.nodes[this.nodes.length - 1] ?? null;
1099
+ addLast(element: E) {
1100
+ if (this.size === 0) {
1101
+ const mid = Math.floor(this.capacity / 2);
1102
+ this._first = mid;
1103
+ this._last = mid;
1104
+ } else {
1105
+ this._last++;
1106
+ }
1107
+ this.nodes[this.last] = element;
1108
+ this._size++;
317
1109
  }
318
1110
 
319
1111
  /**
@@ -325,14 +1117,16 @@ export class ArrayDeque<E> {
325
1117
  * Time Complexity: O(1)
326
1118
  * Space Complexity: O(1)
327
1119
  *
328
- * The get function returns the element at the specified index in an array, or null if the index is out of bounds.
329
- * @param {number} index - The index parameter is a number that represents the position of the element you want to
330
- * retrieve from the array.
331
- * @returns The method is returning the element at the specified index in the `_nodes` array. If the element exists, it
332
- * will be returned. If the element does not exist (i.e., the index is out of bounds), `null` will be returned.
1120
+ * The function `popFirst()` removes and returns the first element in a data structure.
1121
+ * @returns The element of the first element in the data structure.
333
1122
  */
334
- get(index: number): E | null {
335
- return this.nodes[index] ?? null;
1123
+ popFirst() {
1124
+ if (!this.size) return;
1125
+ const element = this.getFirst();
1126
+ delete this.nodes[this.first];
1127
+ this._first++;
1128
+ this._size--;
1129
+ return element;
336
1130
  }
337
1131
 
338
1132
  /**
@@ -344,63 +1138,75 @@ export class ArrayDeque<E> {
344
1138
  * Time Complexity: O(1)
345
1139
  * Space Complexity: O(1)
346
1140
  *
347
- * The set function assigns a value to a specific index in an array.
348
- * @param {number} index - The index parameter is a number that represents the position of the element in the array
349
- * that you want to set a new value for.
350
- * @param {E} value - The value parameter represents the new value that you want to set at the specified index in the
351
- * _nodes array.
352
- * @returns The value that is being set at the specified index in the `_nodes` array.
1141
+ * The `getFirst` function returns the first element in an array-like data structure if it exists.
1142
+ * @returns The element at the first position of the `_nodes` array.
353
1143
  */
354
- set(index: number, value: E) {
355
- return (this.nodes[index] = value);
1144
+ getFirst() {
1145
+ if (this.size) return this.nodes[this.first];
356
1146
  }
357
1147
 
358
1148
  /**
359
- * Time Complexity: O(n)
1149
+ * Time Complexity: O(1)
360
1150
  * Space Complexity: O(1)
361
1151
  */
362
1152
 
363
1153
  /**
364
- * Time Complexity: O(n)
1154
+ * Time Complexity: O(1)
365
1155
  * Space Complexity: O(1)
366
1156
  *
367
- * The insert function adds a value at a specified index in an array.
368
- * @param {number} index - The index parameter specifies the position at which the value should be inserted in the
369
- * array. It is a number that represents the index of the array where the value should be inserted. The index starts
370
- * from 0, so the first element of the array has an index of 0, the second element has
371
- * @param {E} value - The value parameter represents the value that you want to insert into the array at the specified
372
- * index.
373
- * @returns The splice method returns an array containing the removed elements, if any. In this case, since no elements
374
- * are being removed, an empty array will be returned.
1157
+ * The `popLast()` function removes and returns the last element in a data structure.
1158
+ * @returns The element that was removed from the data structure.
375
1159
  */
376
- insert(index: number, value: E) {
377
- return this.nodes.splice(index, 0, value);
1160
+ popLast() {
1161
+ if (!this.size) return;
1162
+ const element = this.getLast();
1163
+ delete this.nodes[this.last];
1164
+ this._last--;
1165
+ this._size--;
1166
+
1167
+ return element;
378
1168
  }
379
1169
 
380
1170
  /**
381
- * Time Complexity: O(n)
1171
+ * Time Complexity: O(1)
382
1172
  * Space Complexity: O(1)
383
1173
  */
384
1174
 
385
1175
  /**
386
- * Time Complexity: O(n)
1176
+ * Time Complexity: O(1)
1177
+ * Space Complexity: O(1)
1178
+ *
1179
+ * The `getLast()` function returns the last element in an array-like data structure.
1180
+ * @returns The last element in the array "_nodes" is being returned.
1181
+ */
1182
+ getLast() {
1183
+ if (this.size) return this.nodes[this.last];
1184
+ }
1185
+
1186
+ /**
1187
+ * Time Complexity: O(1)
1188
+ * Space Complexity: O(1)
1189
+ */
1190
+
1191
+ /**
1192
+ * Time Complexity: O(1)
387
1193
  * Space Complexity: O(1)
388
1194
  *
389
- * The delete function removes an element from an array at a specified index.
390
- * @param {number} index - The index parameter specifies the position of the element to be removed from the array. It
391
- * is a number that represents the index of the element to be removed.
392
- * @returns The method is returning an array containing the removed element.
1195
+ * The get function returns the element at the specified index in an array-like data structure.
1196
+ * @param {number} index - The index parameter is a number that represents the position of the element you want to
1197
+ * retrieve from the array.
1198
+ * @returns The element at the specified index in the `_nodes` array is being returned. If there is no element at that
1199
+ * index, `undefined` is returned.
393
1200
  */
394
- delete(index: number) {
395
- return this.nodes.splice(index, 1);
1201
+ get(index: number) {
1202
+ return this.nodes[this.first + index] || undefined;
396
1203
  }
397
1204
 
398
1205
  /**
399
- * The function checks if an array called "_nodes" is empty.
400
- * @returns The method `isEmpty()` is returning a boolean value. It returns `true` if the length of the `_nodes` array
401
- * is 0, indicating that the array is empty. Otherwise, it returns `false`.
1206
+ * The function checks if the size of a data structure is less than or equal to zero.
1207
+ * @returns The method is returning a boolean element indicating whether the size of the object is less than or equal to 0.
402
1208
  */
403
1209
  isEmpty() {
404
- return this.nodes.length === 0;
1210
+ return this.size <= 0;
405
1211
  }
406
- }
1212
+ }