directed-graph-typed 2.0.4 → 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 +612 -879
  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 +6 -6
  64. package/dist/utils/utils.d.ts +110 -49
  65. package/dist/utils/utils.js +148 -73
  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 +681 -905
  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 +9 -5
  101. package/src/utils/utils.ts +152 -86
@@ -5,15 +5,23 @@
5
5
  * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
6
  * @license MIT License
7
7
  */
8
- import type { DoublyLinkedListOptions, ElementCallback } from '../../types';
8
+
9
+ import type { DoublyLinkedListOptions, ElementCallback, LinearBaseOptions } from '../../types';
9
10
  import { LinearLinkedBase, LinkedListNode } from '../base/linear-base';
10
11
 
12
+ /**
13
+ * Node of a doubly linked list; stores value and prev/next links.
14
+ * @remarks Time O(1), Space O(1)
15
+ * @template E
16
+ */
11
17
  export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
12
18
  /**
13
- * The constructor function initializes the value, next, and previous properties of an object.
14
- * @param {E} value - The "value" parameter is the value that will be stored in the node. It can be of any data type, as it
15
- * is defined as a generic type "E".
19
+ * Create a node.
20
+ * @remarks Time O(1), Space O(1)
21
+ * @param value - Element value to store.
22
+ * @returns New node instance.
16
23
  */
24
+
17
25
  constructor(value: E) {
18
26
  super(value);
19
27
  this._value = value;
@@ -23,26 +31,56 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
23
31
 
24
32
  protected override _next: DoublyLinkedListNode<E> | undefined;
25
33
 
34
+ /**
35
+ * Get the next node link.
36
+ * @remarks Time O(1), Space O(1)
37
+ * @returns Next node or undefined.
38
+ */
39
+
26
40
  override get next(): DoublyLinkedListNode<E> | undefined {
27
41
  return this._next;
28
42
  }
29
43
 
44
+ /**
45
+ * Set the next node link.
46
+ * @remarks Time O(1), Space O(1)
47
+ * @param value - Next node or undefined.
48
+ * @returns void
49
+ */
50
+
30
51
  override set next(value: DoublyLinkedListNode<E> | undefined) {
31
52
  this._next = value;
32
53
  }
33
54
 
34
55
  protected _prev: DoublyLinkedListNode<E> | undefined;
35
56
 
57
+ /**
58
+ * Get the previous node link.
59
+ * @remarks Time O(1), Space O(1)
60
+ * @returns Previous node or undefined.
61
+ */
62
+
36
63
  get prev(): DoublyLinkedListNode<E> | undefined {
37
64
  return this._prev;
38
65
  }
39
66
 
67
+ /**
68
+ * Set the previous node link.
69
+ * @remarks Time O(1), Space O(1)
70
+ * @param value - Previous node or undefined.
71
+ * @returns void
72
+ */
73
+
40
74
  set prev(value: DoublyLinkedListNode<E> | undefined) {
41
75
  this._prev = value;
42
76
  }
43
77
  }
44
78
 
45
79
  /**
80
+ * Doubly linked list with O(1) push/pop/unshift/shift and linear scans.
81
+ * @remarks Time O(1), Space O(1)
82
+ * @template E
83
+ * @template R
46
84
  * 1. Node Structure: Each node contains three parts: a data field, a pointer (or reference) to the previous node, and a pointer to the next node. This structure allows traversal of the linked list in both directions.
47
85
  * 2. Bidirectional Traversal: Unlike singly linked lists, doubly linked lists can be easily traversed forwards or backwards. This makes insertions and deletions in the list more flexible and efficient.
48
86
  * 3. No Centralized Index: Unlike arrays, elements in a linked list are not stored contiguously, so there is no centralized index. Accessing elements in a linked list typically requires traversing from the head or tail node.
@@ -217,6 +255,16 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
217
255
  * this.map = new Map<K, DoublyLinkedListNode<CacheEntry<K, V>>>();
218
256
  * }
219
257
  *
258
+ * // Get the current cache length
259
+ * get length(): number {
260
+ * return this.list.length;
261
+ * }
262
+ *
263
+ * // Check if it is empty
264
+ * get isEmpty(): boolean {
265
+ * return this.list.isEmpty();
266
+ * }
267
+ *
220
268
  * // Get cached value
221
269
  * get(key: K): V | undefined {
222
270
  * const node = this.map.get(key);
@@ -262,12 +310,6 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
262
310
  * }
263
311
  * }
264
312
  *
265
- * // Move the node to the head of the linked list
266
- * private moveToFront(node: DoublyLinkedListNode<CacheEntry<K, V>>): void {
267
- * this.list.delete(node);
268
- * this.list.unshift(node.value);
269
- * }
270
- *
271
313
  * // Delete specific key
272
314
  * delete(key: K): boolean {
273
315
  * const node = this.map.get(key);
@@ -287,14 +329,10 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
287
329
  * this.map.clear();
288
330
  * }
289
331
  *
290
- * // Get the current cache length
291
- * get length(): number {
292
- * return this.list.length;
293
- * }
294
- *
295
- * // Check if it is empty
296
- * get isEmpty(): boolean {
297
- * return this.list.isEmpty();
332
+ * // Move the node to the head of the linked list
333
+ * private moveToFront(node: DoublyLinkedListNode<CacheEntry<K, V>>): void {
334
+ * this.list.delete(node);
335
+ * this.list.unshift(node.value);
298
336
  * }
299
337
  * }
300
338
  *
@@ -476,16 +514,16 @@ export class DoublyLinkedListNode<E = any> extends LinkedListNode<E> {
476
514
  * console.log(scheduler.listProcesses()); // []
477
515
  */
478
516
  export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, DoublyLinkedListNode<E>> {
517
+ protected _equals: (a: E, b: E) => boolean = Object.is as unknown as (a: E, b: E) => boolean;
518
+
479
519
  /**
480
- * This TypeScript constructor initializes a DoublyLinkedList with optional elements and options.
481
- * @param {Iterable<E> | Iterable<R>} elements - The `elements` parameter in the constructor is an
482
- * iterable collection of elements of type `E` or `R`. It is used to initialize the DoublyLinkedList
483
- * with the elements provided in the iterable. If no elements are provided, the default value is an
484
- * empty iterable.
485
- * @param [options] - The `options` parameter in the constructor is of type
486
- * `DoublyLinkedListOptions<E, R>`. It is an optional parameter that allows you to pass additional
487
- * configuration options to customize the behavior of the DoublyLinkedList.
520
+ * Create a DoublyLinkedList and optionally bulk-insert elements.
521
+ * @remarks Time O(N), Space O(N)
522
+ * @param [elements] - Iterable of elements or nodes (or raw records if toElementFn is provided).
523
+ * @param [options] - Options such as maxLen and toElementFn.
524
+ * @returns New DoublyLinkedList instance.
488
525
  */
526
+
489
527
  constructor(
490
528
  elements: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>> = [],
491
529
  options?: DoublyLinkedListOptions<E, R>
@@ -495,9 +533,8 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
495
533
  this._tail = undefined;
496
534
  this._length = 0;
497
535
 
498
- if (options) {
499
- const { maxLen } = options;
500
- if (typeof maxLen === 'number' && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen;
536
+ if (options?.maxLen && Number.isInteger(options.maxLen) && options.maxLen > 0) {
537
+ this._maxLen = options.maxLen;
501
538
  }
502
539
 
503
540
  this.pushMany(elements);
@@ -505,71 +542,87 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
505
542
 
506
543
  protected _head: DoublyLinkedListNode<E> | undefined;
507
544
 
545
+ /**
546
+ * Get the head node.
547
+ * @remarks Time O(1), Space O(1)
548
+ * @returns Head node or undefined.
549
+ */
550
+
508
551
  get head(): DoublyLinkedListNode<E> | undefined {
509
552
  return this._head;
510
553
  }
511
554
 
512
555
  protected _tail: DoublyLinkedListNode<E> | undefined;
513
556
 
557
+ /**
558
+ * Get the tail node.
559
+ * @remarks Time O(1), Space O(1)
560
+ * @returns Tail node or undefined.
561
+ */
562
+
514
563
  get tail(): DoublyLinkedListNode<E> | undefined {
515
564
  return this._tail;
516
565
  }
517
566
 
518
- protected _length: number;
567
+ protected _length = 0;
568
+
569
+ /**
570
+ * Get the number of elements.
571
+ * @remarks Time O(1), Space O(1)
572
+ * @returns Current length.
573
+ */
519
574
 
520
575
  get length(): number {
521
576
  return this._length;
522
577
  }
523
578
 
524
579
  /**
525
- * Time Complexity: O(1)
526
- * Space Complexity: O(1)
527
- *
528
- * The `get first` function returns the first node in a doubly linked list, or undefined if the list is empty.
529
- * @returns The method `get first()` returns the first node of the doubly linked list, or `undefined` if the list is empty.
580
+ * Get the first element value.
581
+ * @remarks Time O(1), Space O(1)
582
+ * @returns First element or undefined.
530
583
  */
584
+
531
585
  get first(): E | undefined {
532
586
  return this.head?.value;
533
587
  }
534
588
 
535
589
  /**
536
- * Time Complexity: O(1)
537
- * Space Complexity: O(1)
538
- *
539
- * The `get last` function returns the last node in a doubly linked list, or undefined if the list is empty.
540
- * @returns The method `get last()` returns the last node of the doubly linked list, or `undefined` if the list is empty.
590
+ * Get the last element value.
591
+ * @remarks Time O(1), Space O(1)
592
+ * @returns Last element or undefined.
541
593
  */
594
+
542
595
  get last(): E | undefined {
543
596
  return this.tail?.value;
544
597
  }
545
598
 
546
599
  /**
547
- * Time Complexity: O(n)
548
- * Space Complexity: O(n)
549
- *
550
- * The `fromArray` function creates a new instance of a DoublyLinkedList and populates it with the elements from the
551
- * given array.
552
- * @param {E[]} data - The `data` parameter is an array of elements of type `E`.
553
- * @returns The `fromArray` function returns a DoublyLinkedList object.
600
+ * Create a new list from an array of elements.
601
+ * @remarks Time O(N), Space O(N)
602
+ * @template E
603
+ * @template R
604
+ * @param this - The constructor (subclass) to instantiate.
605
+ * @param data - Array of elements to insert.
606
+ * @returns A new list populated with the array's elements.
554
607
  */
555
- static fromArray<E>(data: E[]) {
556
- return new DoublyLinkedList<E>(data);
608
+
609
+ static fromArray<E, R = any>(
610
+ this: new (
611
+ elements?: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>,
612
+ options?: DoublyLinkedListOptions<E, R>
613
+ ) => any,
614
+ data: E[]
615
+ ) {
616
+ return new this(data);
557
617
  }
558
618
 
559
619
  /**
560
- * Time Complexity: O(1)
561
- * Space Complexity: O(1)
562
- *
563
- * The function `isNode` in TypeScript checks if a given input is an instance of
564
- * `DoublyLinkedListNode`.
565
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
566
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `isNode` function can
567
- * be one of the following types:
568
- * @returns The `isNode` function is checking if the `elementNodeOrPredicate` parameter is an
569
- * instance of `DoublyLinkedListNode<E>`. If it is, the function returns `true`, indicating that the
570
- * parameter is a `DoublyLinkedListNode<E>`. If it is not an instance of `DoublyLinkedListNode<E>`,
571
- * the function returns `false`.
620
+ * Type guard: check whether the input is a DoublyLinkedListNode.
621
+ * @remarks Time O(1), Space O(1)
622
+ * @param elementNodeOrPredicate - Element, node, or predicate.
623
+ * @returns True if the value is a DoublyLinkedListNode.
572
624
  */
625
+
573
626
  isNode(
574
627
  elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
575
628
  ): elementNodeOrPredicate is DoublyLinkedListNode<E> {
@@ -577,14 +630,12 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
577
630
  }
578
631
 
579
632
  /**
580
- * Time Complexity: O(1)
581
- * Space Complexity: O(1)
582
- *
583
- * The `push` function adds a new element or node to the end of a doubly linked list.
584
- * @param {E | DoublyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the `push`
585
- * method can accept either an element of type `E` or a `DoublyLinkedListNode<E>` object.
586
- * @returns The `push` method is returning a boolean value, specifically `true`.
633
+ * Append an element/node to the tail.
634
+ * @remarks Time O(1), Space O(1)
635
+ * @param elementOrNode - Element or node to append.
636
+ * @returns True when appended.
587
637
  */
638
+
588
639
  push(elementOrNode: E | DoublyLinkedListNode<E>): boolean {
589
640
  const newNode = this._ensureNode(elementOrNode);
590
641
  if (!this.head) {
@@ -601,57 +652,52 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
601
652
  }
602
653
 
603
654
  /**
604
- * Time Complexity: O(1)
605
- * Space Complexity: O(1)
606
- *
607
- * The `pop()` function removes and returns the value of the last element in a linked list.
608
- * @returns The method is returning the value of the removed node.
655
+ * Remove and return the tail element.
656
+ * @remarks Time O(1), Space O(1)
657
+ * @returns Removed element or undefined.
609
658
  */
659
+
610
660
  pop(): E | undefined {
611
661
  if (!this.tail) return undefined;
612
- const removedNode = this.tail;
662
+ const removed = this.tail;
613
663
  if (this.head === this.tail) {
614
664
  this._head = undefined;
615
665
  this._tail = undefined;
616
666
  } else {
617
- this._tail = removedNode.prev;
667
+ this._tail = removed.prev;
618
668
  this.tail!.next = undefined;
619
669
  }
620
670
  this._length--;
621
- return removedNode.value;
671
+ return removed.value;
622
672
  }
623
673
 
624
674
  /**
625
- * Time Complexity: O(1)
626
- * Space Complexity: O(1)
627
- *
628
- * The `shift()` function removes and returns the value of the first element in a doubly linked list.
629
- * @returns The value of the removed node.
675
+ * Remove and return the head element.
676
+ * @remarks Time O(1), Space O(1)
677
+ * @returns Removed element or undefined.
630
678
  */
679
+
631
680
  shift(): E | undefined {
632
681
  if (!this.head) return undefined;
633
- const removedNode = this.head;
682
+ const removed = this.head;
634
683
  if (this.head === this.tail) {
635
684
  this._head = undefined;
636
685
  this._tail = undefined;
637
686
  } else {
638
- this._head = removedNode.next;
687
+ this._head = removed.next;
639
688
  this.head!.prev = undefined;
640
689
  }
641
690
  this._length--;
642
- return removedNode.value;
691
+ return removed.value;
643
692
  }
644
693
 
645
694
  /**
646
- * Time Complexity: O(1)
647
- * Space Complexity: O(1)
648
- *
649
- * The unshift function adds a new element or node to the beginning of a doubly linked list.
650
- * @param {E | DoublyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the
651
- * `unshift` method can be either an element of type `E` or a `DoublyLinkedListNode` containing an
652
- * element of type `E`.
653
- * @returns The `unshift` method is returning a boolean value, specifically `true`.
695
+ * Prepend an element/node to the head.
696
+ * @remarks Time O(1), Space O(1)
697
+ * @param elementOrNode - Element or node to prepend.
698
+ * @returns True when prepended.
654
699
  */
700
+
655
701
  unshift(elementOrNode: E | DoublyLinkedListNode<E>): boolean {
656
702
  const newNode = this._ensureNode(elementOrNode);
657
703
  if (!this.head) {
@@ -668,352 +714,254 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
668
714
  }
669
715
 
670
716
  /**
671
- * Time Complexity: O(k)
672
- * Space Complexity: O(k)
673
- *
674
- * The function `pushMany` iterates over elements and pushes them into a data structure, applying a
675
- * transformation function if provided.
676
- * @param {Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>} elements - The `elements`
677
- * parameter in the `pushMany` function can accept an iterable containing elements of type `E`, `R`,
678
- * or `DoublyLinkedListNode<E>`. The function iterates over each element in the iterable and pushes
679
- * it onto the linked list. If a transformation function `to
680
- * @returns The `pushMany` function is returning an array of boolean values (`ans`) which indicate
681
- * the success or failure of pushing each element into the data structure.
717
+ * Append a sequence of elements/nodes.
718
+ * @remarks Time O(N), Space O(1)
719
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
720
+ * @returns Array of per-element success flags.
682
721
  */
683
- pushMany(elements: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>) {
722
+
723
+ pushMany(elements: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>): boolean[] {
684
724
  const ans: boolean[] = [];
685
725
  for (const el of elements) {
686
- if (this.toElementFn) {
687
- ans.push(this.push(this.toElementFn(el as R)));
688
- continue;
689
- }
690
- ans.push(this.push(el as E | DoublyLinkedListNode<E>));
726
+ if (this.toElementFn) ans.push(this.push(this.toElementFn(el as R)));
727
+ else ans.push(this.push(el as E | DoublyLinkedListNode<E>));
691
728
  }
692
729
  return ans;
693
730
  }
694
731
 
695
732
  /**
696
- * Time Complexity: O(k)
697
- * Space Complexity: O(k)
698
- *
699
- * The function `unshiftMany` iterates through a collection of elements and adds them to the
700
- * beginning of a Doubly Linked List, returning an array of boolean values indicating the success of
701
- * each insertion.
702
- * @param {Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>} elements - The `elements`
703
- * parameter in the `unshiftMany` function can accept an iterable containing elements of type `E`,
704
- * `R`, or `DoublyLinkedListNode<E>`. The function iterates over each element in the iterable and
705
- * performs an `unshift` operation on the doubly linked list
706
- * @returns The `unshiftMany` function returns an array of boolean values indicating the success of
707
- * each unshift operation performed on the elements passed as input.
733
+ * Prepend a sequence of elements/nodes.
734
+ * @remarks Time O(N), Space O(1)
735
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
736
+ * @returns Array of per-element success flags.
708
737
  */
709
- unshiftMany(elements: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>) {
738
+
739
+ unshiftMany(elements: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>): boolean[] {
710
740
  const ans: boolean[] = [];
711
741
  for (const el of elements) {
712
- if (this.toElementFn) {
713
- ans.push(this.unshift(this.toElementFn(el as R)));
714
- continue;
715
- }
716
- ans.push(this.unshift(el as E | DoublyLinkedListNode<E>));
742
+ if (this.toElementFn) ans.push(this.unshift(this.toElementFn(el as R)));
743
+ else ans.push(this.unshift(el as E | DoublyLinkedListNode<E>));
717
744
  }
718
745
  return ans;
719
746
  }
720
747
 
721
748
  /**
722
- * Time Complexity: O(n)
723
- * Space Complexity: O(1)
724
- *
725
- * The `at` function returns the value at a specified index in a linked list, or undefined if the index is out of bounds.
726
- * @param {number} index - The index parameter is a number that represents the position of the element we want to
727
- * retrieve from the list.
728
- * @returns The method is returning the value at the specified index in the linked list. If the index is out of bounds
729
- * or the linked list is empty, it will return undefined.
749
+ * Get the element at a given index.
750
+ * @remarks Time O(N), Space O(1)
751
+ * @param index - Zero-based index.
752
+ * @returns Element or undefined.
730
753
  */
754
+
731
755
  at(index: number): E | undefined {
732
756
  if (index < 0 || index >= this._length) return undefined;
733
757
  let current = this.head;
734
- for (let i = 0; i < index; i++) {
735
- current = current!.next;
736
- }
758
+ for (let i = 0; i < index; i++) current = current!.next;
737
759
  return current!.value;
738
760
  }
739
761
 
740
762
  /**
741
- * Time Complexity: O(n)
742
- * Space Complexity: O(1)
743
- *
744
- * The function `getNodeAt` returns the node at a given index in a doubly linked list, or undefined if the index is out of
745
- * range.
746
- * @param {number} index - The `index` parameter is a number that represents the position of the node we want to
747
- * retrieve from the doubly linked list. It indicates the zero-based index of the node we want to access.
748
- * @returns The method `getNodeAt(index: number)` returns a `DoublyLinkedListNode<E>` object if the index is within the
749
- * valid range of the linked list, otherwise it returns `undefined`.
763
+ * Get the node reference at a given index.
764
+ * @remarks Time O(N), Space O(1)
765
+ * @param index - Zero-based index.
766
+ * @returns Node or undefined.
750
767
  */
768
+
751
769
  getNodeAt(index: number): DoublyLinkedListNode<E> | undefined {
752
770
  if (index < 0 || index >= this._length) return undefined;
753
771
  let current = this.head;
754
- for (let i = 0; i < index; i++) {
755
- current = current!.next;
756
- }
772
+ for (let i = 0; i < index; i++) current = current!.next;
757
773
  return current;
758
774
  }
759
775
 
760
776
  /**
761
- * Time Complexity: O(n)
762
- * Space Complexity: O(1)
763
- *
764
- * This TypeScript function searches for a node in a doubly linked list based on a given element node
765
- * or predicate.
766
- * @param {| E
767
- * | DoublyLinkedListNode<E>
768
- * | ((node: DoublyLinkedListNode<E>) => boolean)
769
- * | undefined} elementNodeOrPredicate - The `getNode` method you provided is used to find a
770
- * node in a doubly linked list based on a given element, node, or predicate function. The
771
- * `elementNodeOrPredicate` parameter can be one of the following:
772
- * @returns The `getNode` method returns a `DoublyLinkedListNode<E>` or `undefined` based on the
773
- * input `elementNodeOrPredicate`. If the input is `undefined`, the method returns `undefined`.
774
- * Otherwise, it iterates through the linked list starting from the head node and applies the
775
- * provided predicate function to each node. If a node satisfies the predicate, that node is
776
- * returned. If
777
+ * Find a node by value, reference, or predicate.
778
+ * @remarks Time O(N), Space O(1)
779
+ * @param [elementNodeOrPredicate] - Element, node, or predicate to match.
780
+ * @returns Matching node or undefined.
777
781
  */
782
+
778
783
  getNode(
779
784
  elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean) | undefined
780
785
  ): DoublyLinkedListNode<E> | undefined {
781
786
  if (elementNodeOrPredicate === undefined) return;
782
- if (this.isNode(elementNodeOrPredicate)) return elementNodeOrPredicate;
787
+
788
+ if (this.isNode(elementNodeOrPredicate)) {
789
+ const target = elementNodeOrPredicate;
790
+
791
+ let cur = this.head;
792
+ while (cur) {
793
+ if (cur === target) return target;
794
+ cur = cur.next;
795
+ }
796
+
797
+ const isMatch = (node: DoublyLinkedListNode<E>) => this._equals(node.value, target.value);
798
+ cur = this.head;
799
+ while (cur) {
800
+ if (isMatch(cur)) return cur;
801
+ cur = cur.next;
802
+ }
803
+ return undefined;
804
+ }
805
+
783
806
  const predicate = this._ensurePredicate(elementNodeOrPredicate);
784
807
  let current = this.head;
785
-
786
808
  while (current) {
787
- if (predicate(current)) {
788
- return current;
789
- }
809
+ if (predicate(current)) return current;
790
810
  current = current.next;
791
811
  }
792
-
793
812
  return undefined;
794
813
  }
795
814
 
796
815
  /**
797
- * Time Complexity: O(n)
798
- * Space Complexity: O(1)
799
- *
800
- * The `addAt` function inserts a new element or node at a specified index in a doubly linked list.
801
- * @param {number} index - The `index` parameter in the `addAt` method represents the position at
802
- * which you want to add a new element or node in the doubly linked list. It indicates the location
803
- * where the new element or node should be inserted.
804
- * @param {E | DoublyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
805
- * `addAt` method can be either a value of type `E` or a `DoublyLinkedListNode<E>` object.
806
- * @returns The `addAt` method returns a boolean value. It returns `true` if the element or node was
807
- * successfully added at the specified index, and `false` if the index is out of bounds (less than 0
808
- * or greater than the length of the list).
816
+ * Insert a new element/node at an index, shifting following nodes.
817
+ * @remarks Time O(N), Space O(1)
818
+ * @param index - Zero-based index.
819
+ * @param newElementOrNode - Element or node to insert.
820
+ * @returns True if inserted.
809
821
  */
822
+
810
823
  addAt(index: number, newElementOrNode: E | DoublyLinkedListNode<E>): boolean {
811
824
  if (index < 0 || index > this._length) return false;
812
- if (index === 0) {
813
- this.unshift(newElementOrNode);
814
- return true;
815
- }
816
- if (index === this._length) {
817
- this.push(newElementOrNode);
818
- return true;
819
- }
825
+ if (index === 0) return this.unshift(newElementOrNode);
826
+ if (index === this._length) return this.push(newElementOrNode);
820
827
 
821
828
  const newNode = this._ensureNode(newElementOrNode);
822
- const prevNode = this.getNodeAt(index - 1);
823
- const nextNode = prevNode!.next;
829
+ const prevNode = this.getNodeAt(index - 1)!;
830
+ const nextNode = prevNode.next!;
824
831
  newNode.prev = prevNode;
825
832
  newNode.next = nextNode;
826
- prevNode!.next = newNode;
827
- nextNode!.prev = newNode;
833
+ prevNode.next = newNode;
834
+ nextNode.prev = newNode;
828
835
  this._length++;
829
836
  return true;
830
837
  }
831
838
 
832
839
  /**
833
- * Time Complexity: O(1) or O(n)
834
- * Space Complexity: O(1)
835
- *
836
- * The `addBefore` function in TypeScript adds a new element or node before an existing element or
837
- * node in a doubly linked list.
838
- * @param {E | DoublyLinkedListNode<E>} existingElementOrNode - The `existingElementOrNode` parameter
839
- * in the `addBefore` method can be either an element of type `E` or a `DoublyLinkedListNode<E>`.
840
- * @param {E | DoublyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter
841
- * represents the element or node that you want to add before the `existingElementOrNode` in a doubly
842
- * linked list.
843
- * @returns The `addBefore` method returns a boolean value - `true` if the new element or node was
844
- * successfully added before the existing element or node, and `false` if the existing element or
845
- * node was not found.
840
+ * Insert a new element/node before an existing one.
841
+ * @remarks Time O(N), Space O(1)
842
+ * @param existingElementOrNode - Existing element or node.
843
+ * @param newElementOrNode - Element or node to insert.
844
+ * @returns True if inserted.
846
845
  */
846
+
847
847
  addBefore(
848
848
  existingElementOrNode: E | DoublyLinkedListNode<E>,
849
849
  newElementOrNode: E | DoublyLinkedListNode<E>
850
850
  ): boolean {
851
- const existingNode: DoublyLinkedListNode<E> | undefined = this.isNode(existingElementOrNode)
851
+ const existingNode = this.isNode(existingElementOrNode)
852
852
  ? existingElementOrNode
853
853
  : this.getNode(existingElementOrNode);
854
+ if (!existingNode) return false;
854
855
 
855
- if (existingNode) {
856
- const newNode = this._ensureNode(newElementOrNode);
857
- newNode.prev = existingNode.prev;
858
- if (existingNode.prev) {
859
- existingNode.prev.next = newNode;
860
- }
861
- newNode.next = existingNode;
862
- existingNode.prev = newNode;
863
- if (existingNode === this.head) {
864
- this._head = newNode;
865
- }
866
- this._length++;
867
- return true;
868
- }
869
-
870
- return false;
856
+ const newNode = this._ensureNode(newElementOrNode);
857
+ newNode.prev = existingNode.prev;
858
+ if (existingNode.prev) existingNode.prev.next = newNode;
859
+ newNode.next = existingNode;
860
+ existingNode.prev = newNode;
861
+ if (existingNode === this.head) this._head = newNode;
862
+ this._length++;
863
+ return true;
871
864
  }
872
865
 
873
866
  /**
874
- * Time Complexity: O(1) or O(n)
875
- * Space Complexity: O(1)
876
- *
877
- * The `addAfter` function in TypeScript adds a new element or node after an existing element or node
878
- * in a doubly linked list.
879
- * @param {E | DoublyLinkedListNode<E>} existingElementOrNode - existingElementOrNode represents the
880
- * element or node in the doubly linked list after which you want to add a new element or node.
881
- * @param {E | DoublyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
882
- * `addAfter` method represents the element or node that you want to add after the existing element
883
- * or node in a doubly linked list. This parameter can be either an element value or a
884
- * `DoublyLinkedListNode` object that you want to insert
885
- * @returns The `addAfter` method returns a boolean value - `true` if the new element or node was
886
- * successfully added after the existing element or node, and `false` if the existing element or node
887
- * was not found in the linked list.
867
+ * Insert a new element/node after an existing one.
868
+ * @remarks Time O(N), Space O(1)
869
+ * @param existingElementOrNode - Existing element or node.
870
+ * @param newElementOrNode - Element or node to insert.
871
+ * @returns True if inserted.
888
872
  */
873
+
889
874
  addAfter(existingElementOrNode: E | DoublyLinkedListNode<E>, newElementOrNode: E | DoublyLinkedListNode<E>): boolean {
890
- const existingNode: DoublyLinkedListNode<E> | undefined = this.isNode(existingElementOrNode)
875
+ const existingNode = this.isNode(existingElementOrNode)
891
876
  ? existingElementOrNode
892
877
  : this.getNode(existingElementOrNode);
878
+ if (!existingNode) return false;
893
879
 
894
- if (existingNode) {
895
- const newNode = this._ensureNode(newElementOrNode);
896
- newNode.next = existingNode.next;
897
- if (existingNode.next) {
898
- existingNode.next.prev = newNode;
899
- }
900
- newNode.prev = existingNode;
901
- existingNode.next = newNode;
902
- if (existingNode === this.tail) {
903
- this._tail = newNode;
904
- }
905
- this._length++;
906
- return true;
907
- }
908
-
909
- return false;
880
+ const newNode = this._ensureNode(newElementOrNode);
881
+ newNode.next = existingNode.next;
882
+ if (existingNode.next) existingNode.next.prev = newNode;
883
+ newNode.prev = existingNode;
884
+ existingNode.next = newNode;
885
+ if (existingNode === this.tail) this._tail = newNode;
886
+ this._length++;
887
+ return true;
910
888
  }
911
889
 
912
890
  /**
913
- * Time Complexity: O(n)
914
- * Space Complexity: O(1)
915
- *
916
- * The function `setAt` updates the value at a specified index in a data structure if the index
917
- * exists.
918
- * @param {number} index - The `index` parameter in the `setAt` method refers to the position in the
919
- * data structure where you want to set a new value.
920
- * @param {E} value - The `value` parameter in the `setAt` method represents the new value that you
921
- * want to set at the specified index in the data structure.
922
- * @returns The `setAt` method returns a boolean value - `true` if the value at the specified index
923
- * is successfully updated, and `false` if the index is out of bounds.
891
+ * Set the element value at an index.
892
+ * @remarks Time O(N), Space O(1)
893
+ * @param index - Zero-based index.
894
+ * @param value - New value.
895
+ * @returns True if updated.
924
896
  */
897
+
925
898
  setAt(index: number, value: E): boolean {
926
899
  const node = this.getNodeAt(index);
927
- if (node) {
928
- node.value = value;
929
- return true;
930
- }
931
- return false;
900
+ if (!node) return false;
901
+ node.value = value;
902
+ return true;
932
903
  }
933
904
 
934
905
  /**
935
- * Time Complexity: O(n)
936
- * Space Complexity: O(1)
937
- *
938
- * The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element.
939
- * @param {number} index - The index parameter represents the position of the element that needs to be deleted in the
940
- * data structure. It is of type number.
941
- * @returns The method `deleteAt` returns the value of the node that was deleted, or `undefined` if the index is out of
942
- * bounds.
906
+ * Delete the element at an index.
907
+ * @remarks Time O(N), Space O(1)
908
+ * @param index - Zero-based index.
909
+ * @returns Removed element or undefined.
943
910
  */
911
+
944
912
  deleteAt(index: number): E | undefined {
945
913
  if (index < 0 || index >= this._length) return;
946
- let deleted: E | undefined;
947
- if (index === 0) {
948
- deleted = this.first;
949
- this.shift();
950
- return deleted;
951
- }
952
- if (index === this._length - 1) {
953
- deleted = this.last;
954
- this.pop();
955
- return deleted;
956
- }
957
-
958
- const removedNode = this.getNodeAt(index);
959
- const prevNode = removedNode!.prev;
960
- const nextNode = removedNode!.next;
961
- prevNode!.next = nextNode;
962
- nextNode!.prev = prevNode;
914
+ if (index === 0) return this.shift();
915
+ if (index === this._length - 1) return this.pop();
916
+
917
+ const removedNode = this.getNodeAt(index)!;
918
+ const prevNode = removedNode.prev!;
919
+ const nextNode = removedNode.next!;
920
+ prevNode.next = nextNode;
921
+ nextNode.prev = prevNode;
963
922
  this._length--;
964
- return removedNode?.value;
923
+ return removedNode.value;
965
924
  }
966
925
 
967
926
  /**
968
- * Time Complexity: O(1) or O(n)
969
- * Space Complexity: O(1)
970
- *
971
- * The `delete` function removes a specified element or node from a doubly linked list if it exists.
972
- * @param {E | DoublyLinkedListNode<E> | undefined} elementOrNode - The `elementOrNode` parameter in
973
- * the `delete` method can accept an element of type `E`, a `DoublyLinkedListNode` of type `E`, or it
974
- * can be `undefined`. This parameter is used to identify the node that needs to be deleted from the
975
- * doubly linked list
976
- * @returns The `delete` method returns a boolean value - `true` if the element or node was
977
- * successfully deleted from the doubly linked list, and `false` if the element or node was not found
978
- * in the list.
927
+ * Delete the first match by value/node.
928
+ * @remarks Time O(N), Space O(1)
929
+ * @param [elementOrNode] - Element or node to remove.
930
+ * @returns True if removed.
979
931
  */
932
+
980
933
  delete(elementOrNode: E | DoublyLinkedListNode<E> | undefined): boolean {
981
- const node: DoublyLinkedListNode<E> | undefined = this.getNode(elementOrNode);
982
-
983
- if (node) {
984
- if (node === this.head) {
985
- this.shift();
986
- } else if (node === this.tail) {
987
- this.pop();
988
- } else {
989
- const prevNode = node.prev;
990
- const nextNode = node.next;
991
- if (prevNode) prevNode.next = nextNode;
992
- if (nextNode) nextNode.prev = prevNode;
993
- this._length--;
994
- }
995
- return true;
934
+ const node = this.getNode(elementOrNode);
935
+ if (!node) return false;
936
+
937
+ if (node === this.head) this.shift();
938
+ else if (node === this.tail) this.pop();
939
+ else {
940
+ const prevNode = node.prev!;
941
+ const nextNode = node.next!;
942
+ prevNode.next = nextNode;
943
+ nextNode.prev = prevNode;
944
+ this._length--;
996
945
  }
997
- return false;
946
+ return true;
998
947
  }
999
948
 
1000
949
  /**
1001
- * Time Complexity: O(1)
1002
- * Space Complexity: O(1)
1003
- *
1004
- * The function checks if a variable has a length greater than zero and returns a boolean value.
1005
- * @returns A boolean value is being returned.
950
+ * Check whether the list is empty.
951
+ * @remarks Time O(1), Space O(1)
952
+ * @returns True if length is 0.
1006
953
  */
954
+
1007
955
  isEmpty(): boolean {
1008
956
  return this._length === 0;
1009
957
  }
1010
958
 
1011
959
  /**
1012
- * Time Complexity: O(1)
1013
- * Space Complexity: O(1)
1014
- *
1015
- * The `clear` function resets the linked list by setting the head, tail, and length to undefined and 0 respectively.
960
+ * Remove all nodes and reset length.
961
+ * @remarks Time O(N), Space O(1)
962
+ * @returns void
1016
963
  */
964
+
1017
965
  clear(): void {
1018
966
  this._head = undefined;
1019
967
  this._tail = undefined;
@@ -1021,17 +969,12 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
1021
969
  }
1022
970
 
1023
971
  /**
1024
- * Time Complexity: O(n)
1025
- * Space Complexity: O(1)
1026
- *
1027
- * This function retrieves an element from a doubly linked list based on a given element
1028
- * node or predicate.
1029
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
1030
- * elementNodeOrPredicate - The `get` method takes in a parameter called `elementNodeOrPredicate`,
1031
- * which can be one of the following types:
1032
- * @returns The `get` method returns the value of the first node in the doubly linked list that
1033
- * satisfies the provided predicate function. If no such node is found, it returns `undefined`.
972
+ * Find the first value matching a predicate scanning forward.
973
+ * @remarks Time O(N), Space O(1)
974
+ * @param elementNodeOrPredicate - Element, node, or predicate to match.
975
+ * @returns Matched value or undefined.
1034
976
  */
977
+
1035
978
  search(
1036
979
  elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
1037
980
  ): E | undefined {
@@ -1045,18 +988,12 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
1045
988
  }
1046
989
 
1047
990
  /**
1048
- * Time Complexity: O(n)
1049
- * Space Complexity: O(1)
1050
- *
1051
- * The `getBackward` function searches for a specific element in a doubly linked list starting from
1052
- * the tail and moving backwards.
1053
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
1054
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `getBackward`
1055
- * function can be one of the following types:
1056
- * @returns The `getBackward` method returns the value of the element node that matches the provided
1057
- * predicate when traversing the doubly linked list backwards. If no matching element is found, it
1058
- * returns `undefined`.
991
+ * Find the first value matching a predicate scanning backward.
992
+ * @remarks Time O(N), Space O(1)
993
+ * @param elementNodeOrPredicate - Element, node, or predicate to match.
994
+ * @returns Matched value or undefined.
1059
995
  */
996
+
1060
997
  getBackward(
1061
998
  elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
1062
999
  ): E | undefined {
@@ -1070,11 +1007,11 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
1070
1007
  }
1071
1008
 
1072
1009
  /**
1073
- * Time Complexity: O(n)
1074
- * Space Complexity: O(1)
1075
- *
1076
- * The `reverse` function reverses the order of the elements in a doubly linked list.
1010
+ * Reverse the list in place.
1011
+ * @remarks Time O(N), Space O(1)
1012
+ * @returns This list.
1077
1013
  */
1014
+
1078
1015
  reverse(): this {
1079
1016
  let current = this.head;
1080
1017
  [this._head, this._tail] = [this.tail, this.head];
@@ -1087,226 +1024,185 @@ export class DoublyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, D
1087
1024
  }
1088
1025
 
1089
1026
  /**
1090
- * Time Complexity: O(n)
1091
- * Space Complexity: O(n)
1092
- *
1093
- * The `clone` function creates a new instance of the `DoublyLinkedList` class with the same values
1094
- * as the original list.
1095
- * @returns The `clone()` method is returning a new instance of the `DoublyLinkedList` class, which
1096
- * is a copy of the original list.
1027
+ * Set the equality comparator used to compare values.
1028
+ * @remarks Time O(1), Space O(1)
1029
+ * @param equals - Equality predicate (a, b) → boolean.
1030
+ * @returns This list.
1097
1031
  */
1098
- clone(): this {
1099
- return new DoublyLinkedList<E, R>(this, { toElementFn: this._toElementFn, maxLen: this._maxLen }) as this;
1032
+
1033
+ setEquality(equals: (a: E, b: E) => boolean): this {
1034
+ this._equals = equals;
1035
+ return this;
1100
1036
  }
1101
1037
 
1102
1038
  /**
1103
- * Time Complexity: O(n)
1104
- * Space Complexity: O(n)
1105
- *
1106
- * The `filter` function creates a new DoublyLinkedList by iterating over the elements of the current
1107
- * list and applying a callback function to each element, returning only the elements for which the
1108
- * callback function returns true.
1109
- * @param callback - The `callback` parameter is a function that will be called for each element in
1110
- * the DoublyLinkedList. It takes three arguments: the current element, the index of the current
1111
- * element, and the DoublyLinkedList itself. The callback function should return a boolean value
1112
- * indicating whether the current element should be included
1113
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
1114
- * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be
1115
- * passed as the `this` value to the `callback` function. If `thisArg` is
1116
- * @returns The `filter` method is returning a new `DoublyLinkedList` object that contains the
1117
- * elements that pass the filter condition specified by the `callback` function.
1039
+ * Deep clone this list (values are copied by reference).
1040
+ * @remarks Time O(N), Space O(N)
1041
+ * @returns A new list with the same element sequence.
1118
1042
  */
1119
- filter(callback: ElementCallback<E, R, boolean>, thisArg?: any): DoublyLinkedList<E, R> {
1120
- const filteredList = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
1121
- let index = 0;
1122
- for (const current of this) {
1123
- if (callback.call(thisArg, current, index, this)) {
1124
- filteredList.push(current);
1125
- }
1126
- index++;
1127
- }
1128
- return filteredList;
1043
+
1044
+ clone(): this {
1045
+ const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
1046
+ for (const v of this) out.push(v);
1047
+ return out;
1129
1048
  }
1130
1049
 
1131
1050
  /**
1132
- * Time Complexity: O(n)
1133
- * Space Complexity: O(n)
1134
- *
1135
- * The `map` function takes a callback function and returns a new DoublyLinkedList with the results
1136
- * of applying the callback to each element in the original list.
1137
- * @param callback - The callback parameter is a function that will be called for each element in the
1138
- * original DoublyLinkedList. It takes three arguments: current (the current element being
1139
- * processed), index (the index of the current element), and this (the original DoublyLinkedList).
1140
- * The callback function should return a value of type
1141
- * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to
1142
- * convert the raw element (`RR`) to the desired element type (`T`). It takes the raw element as
1143
- * input and returns the converted element. If this parameter is not provided, the raw element will
1144
- * be used as is.
1145
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
1146
- * specify the value of `this` within the callback function. It is used to set the context or scope
1147
- * in which the callback function will be executed. If `thisArg` is provided, it will be used as the
1148
- * value of
1149
- * @returns a new instance of the `DoublyLinkedList` class with elements of type `T` and `RR`.
1051
+ * Filter values into a new list of the same class.
1052
+ * @remarks Time O(N), Space O(N)
1053
+ * @param callback - Predicate (value, index, list) → boolean to keep value.
1054
+ * @param [thisArg] - Value for `this` inside the callback.
1055
+ * @returns A new list with kept values.
1150
1056
  */
1151
- map<EM, RM>(
1152
- callback: ElementCallback<E, R, EM>,
1153
- toElementFn?: (rawElement: RM) => EM,
1154
- thisArg?: any
1155
- ): DoublyLinkedList<EM, RM> {
1156
- const mappedList = new DoublyLinkedList<EM, RM>([], { toElementFn, maxLen: this._maxLen });
1157
- let index = 0;
1158
- for (const current of this) {
1159
- mappedList.push(callback.call(thisArg, current, index, this));
1160
- index++;
1161
- }
1162
1057
 
1163
- return mappedList;
1058
+ filter(callback: ElementCallback<E, R, boolean>, thisArg?: any): this {
1059
+ const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
1060
+ let index = 0;
1061
+ for (const v of this) if (callback.call(thisArg, v, index++, this)) out.push(v);
1062
+ return out;
1164
1063
  }
1165
1064
 
1166
1065
  /**
1167
- * Time Complexity: O(n)
1168
- * Space Complexity: O(1)
1169
- *
1170
- * The function `countOccurrences` iterates through a doubly linked list and counts the occurrences
1171
- * of a specified element or nodes that satisfy a given predicate.
1172
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementOrNode
1173
- * - The `elementOrNode` parameter in the `countOccurrences` method can accept three types of values:
1174
- * @returns The `countOccurrences` method returns the number of occurrences of the specified element,
1175
- * node, or predicate function in the doubly linked list.
1066
+ * Map values into a new list of the same class.
1067
+ * @remarks Time O(N), Space O(N)
1068
+ * @param callback - Mapping function (value, index, list) → newValue.
1069
+ * @param [thisArg] - Value for `this` inside the callback.
1070
+ * @returns A new list with mapped values.
1176
1071
  */
1177
- countOccurrences(elementOrNode: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)): number {
1178
- const predicate = this._ensurePredicate(elementOrNode);
1179
- let count = 0;
1180
- let current = this.head;
1181
1072
 
1182
- while (current) {
1183
- if (predicate(current)) {
1184
- count++;
1185
- }
1186
- current = current.next;
1073
+ mapSame(callback: ElementCallback<E, R, E>, thisArg?: any): this {
1074
+ const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
1075
+ let index = 0;
1076
+ for (const v of this) {
1077
+ const mv = thisArg === undefined ? callback(v, index++, this) : callback.call(thisArg, v, index++, this);
1078
+ out.push(mv);
1187
1079
  }
1188
-
1189
- return count;
1080
+ return out;
1190
1081
  }
1191
1082
 
1192
1083
  /**
1193
- * The function returns an iterator that iterates over the values of a linked list.
1084
+ * Map values into a new list (possibly different element type).
1085
+ * @remarks Time O(N), Space O(N)
1086
+ * @template EM
1087
+ * @template RM
1088
+ * @param callback - Mapping function (value, index, list) → newElement.
1089
+ * @param [options] - Options for the output list (e.g., maxLen, toElementFn).
1090
+ * @param [thisArg] - Value for `this` inside the callback.
1091
+ * @returns A new DoublyLinkedList with mapped values.
1194
1092
  */
1195
- protected *_getIterator(): IterableIterator<E> {
1196
- let current = this.head;
1197
1093
 
1198
- while (current) {
1199
- yield current.value;
1200
- current = current.next;
1201
- }
1094
+ map<EM, RM>(
1095
+ callback: ElementCallback<E, R, EM>,
1096
+ options?: DoublyLinkedListOptions<EM, RM>,
1097
+ thisArg?: any
1098
+ ): DoublyLinkedList<EM, RM> {
1099
+ const out = this._createLike<EM, RM>([], { ...(options ?? {}), maxLen: this._maxLen });
1100
+ let index = 0;
1101
+ for (const v of this) out.push(callback.call(thisArg, v, index++, this));
1102
+ return out;
1202
1103
  }
1203
1104
 
1204
1105
  /**
1205
- * The function returns an iterator that iterates over the elements of a data structure in reverse
1206
- * order.
1106
+ * (Protected) Create or return a node for the given input (node or raw element).
1107
+ * @remarks Time O(1), Space O(1)
1108
+ * @param elementOrNode - Element value or node to normalize.
1109
+ * @returns A DoublyLinkedListNode for the provided input.
1207
1110
  */
1208
- protected *_getReverseIterator(): IterableIterator<E> {
1209
- let current = this.tail;
1210
1111
 
1211
- while (current) {
1212
- yield current.value;
1213
- current = current.prev;
1214
- }
1112
+ protected _ensureNode(elementOrNode: E | DoublyLinkedListNode<E>) {
1113
+ if (this.isNode(elementOrNode)) return elementOrNode;
1114
+ return new DoublyLinkedListNode<E>(elementOrNode);
1215
1115
  }
1216
1116
 
1217
1117
  /**
1218
- * The function returns an iterator that iterates over the nodes of a doubly linked list starting
1219
- * from the head.
1118
+ * (Protected) Normalize input into a predicate over nodes.
1119
+ * @remarks Time O(1), Space O(1)
1120
+ * @param elementNodeOrPredicate - Element, node, or node predicate.
1121
+ * @returns A predicate function taking a node and returning true/false.
1220
1122
  */
1221
- protected *_getNodeIterator(): IterableIterator<DoublyLinkedListNode<E>> {
1222
- let current = this.head;
1223
1123
 
1224
- while (current) {
1225
- yield current;
1226
- current = current.next;
1124
+ protected _ensurePredicate(
1125
+ elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
1126
+ ): (node: DoublyLinkedListNode<E>) => boolean {
1127
+ if (this.isNode(elementNodeOrPredicate)) {
1128
+ const target = elementNodeOrPredicate;
1129
+ return (node: DoublyLinkedListNode<E>) => node === target;
1227
1130
  }
1131
+ if (typeof elementNodeOrPredicate === 'function') {
1132
+ return elementNodeOrPredicate as (node: DoublyLinkedListNode<E>) => boolean;
1133
+ }
1134
+ const value = elementNodeOrPredicate as E;
1135
+ return (node: DoublyLinkedListNode<E>) => this._equals(node.value, value);
1228
1136
  }
1229
1137
 
1230
- // protected *_getReverseNodeIterator(): IterableIterator<DoublyLinkedListNode<E>> {
1231
- // const reversedArr = [...this._getNodeIterator()].reverse();
1232
- //
1233
- // for (const item of reversedArr) {
1234
- // yield item;
1235
- // }
1236
- // }
1237
-
1238
1138
  /**
1239
- * The function `_isPredicate` checks if the input is a function that takes a `DoublyLinkedListNode`
1240
- * as an argument and returns a boolean.
1241
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
1242
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following
1243
- * types:
1244
- * @returns The _isPredicate method is returning a boolean value indicating whether the
1245
- * elementNodeOrPredicate parameter is a function or not. If the elementNodeOrPredicate is a
1246
- * function, the method will return true, indicating that it is a predicate function.
1139
+ * (Protected) Get the previous node of a given node.
1140
+ * @remarks Time O(1), Space O(1)
1141
+ * @param node - A node in the list.
1142
+ * @returns Previous node or undefined.
1247
1143
  */
1248
- protected _isPredicate(
1249
- elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
1250
- ): elementNodeOrPredicate is (node: DoublyLinkedListNode<E>) => boolean {
1251
- return typeof elementNodeOrPredicate === 'function';
1144
+
1145
+ protected _getPrevNode(node: DoublyLinkedListNode<E>): DoublyLinkedListNode<E> | undefined {
1146
+ return node.prev;
1252
1147
  }
1253
1148
 
1254
1149
  /**
1255
- * The function `_ensureNode` ensures that the input is a valid node in a doubly linked list.
1256
- * @param {E | DoublyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter can be either
1257
- * an element of type `E` or a `DoublyLinkedListNode` containing an element of type `E`.
1258
- * @returns If the `elementOrNode` parameter is already a `DoublyLinkedListNode`, it will be returned
1259
- * as is. Otherwise, a new `DoublyLinkedListNode` instance will be created with the `elementOrNode`
1260
- * value and returned.
1150
+ * (Protected) Create an empty instance of the same concrete class.
1151
+ * @remarks Time O(1), Space O(1)
1152
+ * @param [options] - Options forwarded to the constructor.
1153
+ * @returns An empty like-kind list instance.
1261
1154
  */
1262
- protected _ensureNode(elementOrNode: E | DoublyLinkedListNode<E>) {
1263
- if (this.isNode(elementOrNode)) return elementOrNode;
1264
1155
 
1265
- return new DoublyLinkedListNode<E>(elementOrNode);
1156
+ protected override _createInstance(options?: LinearBaseOptions<E, R>): this {
1157
+ const Ctor = this.constructor as new (
1158
+ elements?: Iterable<E> | Iterable<R> | Iterable<DoublyLinkedListNode<E>>,
1159
+ options?: DoublyLinkedListOptions<E, R>
1160
+ ) => this;
1161
+ return new Ctor([], options as DoublyLinkedListOptions<E, R> | undefined);
1266
1162
  }
1267
1163
 
1268
1164
  /**
1269
- * The function `_ensurePredicate` in TypeScript ensures that the input is either a node, a predicate
1270
- * function, or a value to compare with the node's value.
1271
- * @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
1272
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following
1273
- * types:
1274
- * @returns A function is being returned that takes a `DoublyLinkedListNode` as a parameter and
1275
- * returns a boolean value based on the conditions specified in the code.
1165
+ * (Protected) Create a like-kind instance and seed it from an iterable.
1166
+ * @remarks Time O(N), Space O(N)
1167
+ * @template EM
1168
+ * @template RM
1169
+ * @param [elements] - Iterable used to seed the new list.
1170
+ * @param [options] - Options forwarded to the constructor.
1171
+ * @returns A like-kind DoublyLinkedList instance.
1276
1172
  */
1277
- protected _ensurePredicate(
1278
- elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
1279
- ) {
1280
- if (this.isNode(elementNodeOrPredicate)) return (node: DoublyLinkedListNode<E>) => node === elementNodeOrPredicate;
1281
1173
 
1282
- if (this._isPredicate(elementNodeOrPredicate)) return elementNodeOrPredicate;
1174
+ protected _createLike<EM = E, RM = R>(
1175
+ elements: Iterable<EM> | Iterable<RM> | Iterable<DoublyLinkedListNode<EM>> = [],
1176
+ options?: DoublyLinkedListOptions<EM, RM>
1177
+ ): DoublyLinkedList<EM, RM> {
1178
+ const Ctor = this.constructor as new (
1179
+ elements?: Iterable<EM> | Iterable<RM> | Iterable<DoublyLinkedListNode<EM>>,
1180
+ options?: DoublyLinkedListOptions<EM, RM>
1181
+ ) => DoublyLinkedList<EM, RM>;
1182
+ return new Ctor(elements, options);
1183
+ }
1283
1184
 
1284
- return (node: DoublyLinkedListNode<E>) => node.value === elementNodeOrPredicate;
1185
+ protected *_getIterator(): IterableIterator<E> {
1186
+ let current = this.head;
1187
+ while (current) {
1188
+ yield current.value;
1189
+ current = current.next;
1190
+ }
1285
1191
  }
1286
1192
 
1287
- /**
1288
- * The function `_createInstance` returns a new instance of `DoublyLinkedList` with the specified
1289
- * options.
1290
- * @param [options] - The `options` parameter in the `_createInstance` method is of type
1291
- * `DoublyLinkedListOptions<E, R>`. It is an optional parameter that allows you to pass additional
1292
- * configuration options when creating a new instance of the `DoublyLinkedList` class.
1293
- * @returns An instance of the `DoublyLinkedList` class with an empty array and the provided options
1294
- * is being returned, cast as the current class type.
1295
- */
1296
- protected override _createInstance(options?: DoublyLinkedListOptions<E, R>): this {
1297
- return new DoublyLinkedList<E, R>([], options) as this;
1193
+ protected *_getReverseIterator(): IterableIterator<E> {
1194
+ let current = this.tail;
1195
+ while (current) {
1196
+ yield current.value;
1197
+ current = current.prev;
1198
+ }
1298
1199
  }
1299
1200
 
1300
- /**
1301
- * The function `_getPrevNode` returns the previous node of a given node in a doubly linked list.
1302
- * @param node - The parameter `node` in the `_getPrevNode` method is of type
1303
- * `DoublyLinkedListNode<E>`, which represents a node in a doubly linked list containing an element
1304
- * of type `E`.
1305
- * @returns The `_getPrevNode` method is returning the previous node of the input `node` in a doubly
1306
- * linked list. If the input node has a previous node, it will return that node. Otherwise, it will
1307
- * return `undefined`.
1308
- */
1309
- protected _getPrevNode(node: DoublyLinkedListNode<E>): DoublyLinkedListNode<E> | undefined {
1310
- return node.prev;
1201
+ protected *_getNodeIterator(): IterableIterator<DoublyLinkedListNode<E>> {
1202
+ let current = this.head;
1203
+ while (current) {
1204
+ yield current;
1205
+ current = current.next;
1206
+ }
1311
1207
  }
1312
1208
  }