doubly-linked-list-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 (102) hide show
  1. package/README.md +14 -14
  2. package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
  3. package/dist/data-structures/base/iterable-element-base.js +149 -107
  4. package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
  5. package/dist/data-structures/base/iterable-entry-base.js +59 -116
  6. package/dist/data-structures/base/linear-base.d.ts +250 -192
  7. package/dist/data-structures/base/linear-base.js +137 -274
  8. package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  9. package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
  10. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  11. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
  12. package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
  13. package/dist/data-structures/binary-tree/avl-tree.js +208 -195
  14. package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
  15. package/dist/data-structures/binary-tree/binary-tree.js +612 -879
  16. package/dist/data-structures/binary-tree/bst.d.ts +258 -306
  17. package/dist/data-structures/binary-tree/bst.js +505 -481
  18. package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  19. package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
  20. package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
  21. package/dist/data-structures/binary-tree/tree-counter.js +172 -203
  22. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  23. package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
  24. package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
  25. package/dist/data-structures/graph/abstract-graph.js +267 -237
  26. package/dist/data-structures/graph/directed-graph.d.ts +108 -224
  27. package/dist/data-structures/graph/directed-graph.js +146 -233
  28. package/dist/data-structures/graph/map-graph.d.ts +49 -55
  29. package/dist/data-structures/graph/map-graph.js +56 -59
  30. package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
  31. package/dist/data-structures/graph/undirected-graph.js +129 -149
  32. package/dist/data-structures/hash/hash-map.d.ts +164 -338
  33. package/dist/data-structures/hash/hash-map.js +270 -457
  34. package/dist/data-structures/heap/heap.d.ts +214 -289
  35. package/dist/data-structures/heap/heap.js +340 -349
  36. package/dist/data-structures/heap/max-heap.d.ts +11 -47
  37. package/dist/data-structures/heap/max-heap.js +11 -66
  38. package/dist/data-structures/heap/min-heap.d.ts +12 -47
  39. package/dist/data-structures/heap/min-heap.js +11 -66
  40. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  41. package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
  42. package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  43. package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
  44. package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  45. package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
  46. package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  47. package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
  48. package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  49. package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
  50. package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
  51. package/dist/data-structures/priority-queue/priority-queue.js +8 -83
  52. package/dist/data-structures/queue/deque.d.ts +227 -254
  53. package/dist/data-structures/queue/deque.js +309 -348
  54. package/dist/data-structures/queue/queue.d.ts +180 -201
  55. package/dist/data-structures/queue/queue.js +265 -248
  56. package/dist/data-structures/stack/stack.d.ts +124 -102
  57. package/dist/data-structures/stack/stack.js +181 -125
  58. package/dist/data-structures/trie/trie.d.ts +164 -165
  59. package/dist/data-structures/trie/trie.js +189 -172
  60. package/dist/interfaces/binary-tree.d.ts +56 -6
  61. package/dist/interfaces/graph.d.ts +16 -0
  62. package/dist/types/data-structures/base/base.d.ts +1 -1
  63. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
  64. package/dist/types/utils/utils.d.ts +6 -6
  65. package/dist/utils/utils.d.ts +110 -49
  66. package/dist/utils/utils.js +148 -73
  67. package/package.json +2 -2
  68. package/src/data-structures/base/iterable-element-base.ts +238 -115
  69. package/src/data-structures/base/iterable-entry-base.ts +96 -120
  70. package/src/data-structures/base/linear-base.ts +271 -277
  71. package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
  72. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
  73. package/src/data-structures/binary-tree/avl-tree.ts +239 -206
  74. package/src/data-structures/binary-tree/binary-tree.ts +681 -905
  75. package/src/data-structures/binary-tree/bst.ts +568 -570
  76. package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
  77. package/src/data-structures/binary-tree/tree-counter.ts +199 -218
  78. package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
  79. package/src/data-structures/graph/abstract-graph.ts +339 -264
  80. package/src/data-structures/graph/directed-graph.ts +146 -236
  81. package/src/data-structures/graph/map-graph.ts +63 -60
  82. package/src/data-structures/graph/undirected-graph.ts +129 -152
  83. package/src/data-structures/hash/hash-map.ts +274 -496
  84. package/src/data-structures/heap/heap.ts +389 -402
  85. package/src/data-structures/heap/max-heap.ts +12 -76
  86. package/src/data-structures/heap/min-heap.ts +13 -76
  87. package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
  88. package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
  89. package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
  90. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
  91. package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
  92. package/src/data-structures/priority-queue/priority-queue.ts +3 -92
  93. package/src/data-structures/queue/deque.ts +381 -357
  94. package/src/data-structures/queue/queue.ts +310 -264
  95. package/src/data-structures/stack/stack.ts +217 -131
  96. package/src/data-structures/trie/trie.ts +240 -175
  97. package/src/interfaces/binary-tree.ts +240 -6
  98. package/src/interfaces/graph.ts +37 -0
  99. package/src/types/data-structures/base/base.ts +5 -5
  100. package/src/types/data-structures/graph/abstract-graph.ts +5 -0
  101. package/src/types/utils/utils.ts +9 -5
  102. package/src/utils/utils.ts +152 -86
@@ -1,33 +1,60 @@
1
1
  "use strict";
2
+ /**
3
+ * data-structure-typed
4
+ *
5
+ * @author Pablo Zeng
6
+ * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
7
+ * @license MIT License
8
+ */
2
9
  Object.defineProperty(exports, "__esModule", { value: true });
3
10
  exports.SinglyLinkedList = exports.SinglyLinkedListNode = void 0;
4
11
  const linear_base_1 = require("../base/linear-base");
12
+ /**
13
+ * Node of a singly linked list; stores value and the next link.
14
+ * @remarks Time O(1), Space O(1)
15
+ * @template E
16
+ */
5
17
  class SinglyLinkedListNode extends linear_base_1.LinkedListNode {
6
18
  /**
7
- * The constructor function initializes an instance of a class with a given value and sets the next property to undefined.
8
- * @param {E} value - The "value" parameter is of type E, which means it can be any data type. It represents the value that
9
- * will be stored in the node of a linked list.
19
+ * Create a list node.
20
+ * @remarks Time O(1), Space O(1)
21
+ * @param value - Element value to store.
22
+ * @returns New node instance.
10
23
  */
11
24
  constructor(value) {
12
25
  super(value);
13
26
  this._value = value;
14
27
  this._next = undefined;
15
28
  }
29
+ /**
30
+ * Get the next node.
31
+ * @remarks Time O(1), Space O(1)
32
+ * @returns Next node or undefined.
33
+ */
16
34
  get next() {
17
35
  return this._next;
18
36
  }
37
+ /**
38
+ * Set the next node.
39
+ * @remarks Time O(1), Space O(1)
40
+ * @param value - Next node or undefined.
41
+ * @returns void
42
+ */
19
43
  set next(value) {
20
44
  this._next = value;
21
45
  }
22
46
  }
23
47
  exports.SinglyLinkedListNode = SinglyLinkedListNode;
24
48
  /**
49
+ * Singly linked list with O(1) push/pop-like ends operations and linear scans.
50
+ * @remarks Time O(1), Space O(1)
51
+ * @template E
52
+ * @template R
25
53
  * 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.
26
54
  * 2. Bidirectional Traversal: Unlike doubly linked lists, singly linked lists can be easily traversed forwards but not backwards.
27
55
  * 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.
28
56
  * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays.
29
57
  * Caution: Although our linked list classes provide methods such as at, setAt, addAt, and indexOf that are based on array indices, their time complexity, like that of the native Array.lastIndexOf, is 𝑂(𝑛). If you need to use these methods frequently, you might want to consider other data structures, such as Deque or Queue (designed for random access). Similarly, since the native Array.shift method has a time complexity of 𝑂(𝑛), using an array to simulate a queue can be inefficient. In such cases, you should use Queue or Deque, as these data structures leverage deferred array rearrangement, effectively reducing the average time complexity to 𝑂(1).
30
- *
31
58
  * @example
32
59
  * // implementation of a basic text editor
33
60
  * class TextEditor {
@@ -96,60 +123,88 @@ exports.SinglyLinkedListNode = SinglyLinkedListNode;
96
123
  * console.log(editor.getText()); // 'Haello'
97
124
  */
98
125
  class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
126
+ /**
127
+ * Create a SinglyLinkedList and optionally bulk-insert elements.
128
+ * @remarks Time O(N), Space O(N)
129
+ * @param [elements] - Iterable of elements or nodes (or raw records if toElementFn is provided).
130
+ * @param [options] - Options such as maxLen and toElementFn.
131
+ * @returns New SinglyLinkedList instance.
132
+ */
99
133
  constructor(elements = [], options) {
100
134
  super(options);
135
+ this._equals = Object.is;
101
136
  this._length = 0;
102
- if (options) {
103
- }
104
137
  this.pushMany(elements);
105
138
  }
139
+ /**
140
+ * Get the head node.
141
+ * @remarks Time O(1), Space O(1)
142
+ * @returns Head node or undefined.
143
+ */
106
144
  get head() {
107
145
  return this._head;
108
146
  }
147
+ /**
148
+ * Get the tail node.
149
+ * @remarks Time O(1), Space O(1)
150
+ * @returns Tail node or undefined.
151
+ */
109
152
  get tail() {
110
153
  return this._tail;
111
154
  }
155
+ /**
156
+ * Get the number of elements.
157
+ * @remarks Time O(1), Space O(1)
158
+ * @returns Current length.
159
+ */
160
+ get length() {
161
+ return this._length;
162
+ }
163
+ /**
164
+ * Get the first element value.
165
+ * @remarks Time O(1), Space O(1)
166
+ * @returns First element or undefined.
167
+ */
112
168
  get first() {
113
169
  var _a;
114
170
  return (_a = this.head) === null || _a === void 0 ? void 0 : _a.value;
115
171
  }
172
+ /**
173
+ * Get the last element value.
174
+ * @remarks Time O(1), Space O(1)
175
+ * @returns Last element or undefined.
176
+ */
116
177
  get last() {
117
178
  var _a;
118
179
  return (_a = this.tail) === null || _a === void 0 ? void 0 : _a.value;
119
180
  }
120
- get length() {
121
- return this._length;
122
- }
123
181
  /**
124
- * Time Complexity: O(n)
125
- * Space Complexity: O(n)
126
- *
127
- * The `fromArray` function creates a new SinglyLinkedList instance and populates it with the elements from the given
128
- * array.
129
- * @param {E[]} data - The `data` parameter is an array of elements of type `E`.
130
- * @returns The `fromArray` function returns a `SinglyLinkedList` object.
182
+ * Create a new list from an iterable of elements.
183
+ * @remarks Time O(N), Space O(N)
184
+ * @template E
185
+ * @template R
186
+ * @template S
187
+ * @param this - The constructor (subclass) to instantiate.
188
+ * @param data - Iterable of elements to insert.
189
+ * @param [options] - Options forwarded to the constructor.
190
+ * @returns A new list populated with the iterable's elements.
131
191
  */
132
- static fromArray(data) {
133
- const singlyLinkedList = new SinglyLinkedList();
134
- for (const item of data) {
135
- singlyLinkedList.push(item);
136
- }
137
- return singlyLinkedList;
192
+ static from(data, options) {
193
+ const list = new this([], options);
194
+ for (const x of data)
195
+ list.push(x);
196
+ return list;
138
197
  }
139
198
  /**
140
- * Time Complexity: O(1)
141
- * Space Complexity: O(1)
142
- *
143
- * The `push` function adds a new element or node to the end of a singly linked list.
144
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the `push`
145
- * method can accept either an element of type `E` or a `SinglyLinkedListNode<E>` object.
146
- * @returns The `push` method is returning a boolean value, specifically `true`.
199
+ * Append an element/node to the tail.
200
+ * @remarks Time O(1), Space O(1)
201
+ * @param elementOrNode - Element or node to append.
202
+ * @returns True when appended.
147
203
  */
148
204
  push(elementOrNode) {
149
205
  const newNode = this._ensureNode(elementOrNode);
150
206
  if (!this.head) {
151
- this._head = newNode;
152
- this._tail = newNode;
207
+ this._head = this._tail = newNode;
153
208
  }
154
209
  else {
155
210
  this.tail.next = newNode;
@@ -161,12 +216,9 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
161
216
  return true;
162
217
  }
163
218
  /**
164
- * Time Complexity: O(n)
165
- * Space Complexity: O(1)
166
- *
167
- * The `pop` function removes and returns the value of the last element in a linked list.
168
- * @returns The method is returning the value of the element that is being popped from the end of the
169
- * list.
219
+ * Remove and return the tail element.
220
+ * @remarks Time O(N), Space O(1)
221
+ * @returns Removed element or undefined.
170
222
  */
171
223
  pop() {
172
224
  if (!this.head)
@@ -179,9 +231,8 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
179
231
  return value;
180
232
  }
181
233
  let current = this.head;
182
- while (current.next !== this.tail) {
234
+ while (current.next !== this.tail)
183
235
  current = current.next;
184
- }
185
236
  const value = this.tail.value;
186
237
  current.next = undefined;
187
238
  this._tail = current;
@@ -189,36 +240,30 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
189
240
  return value;
190
241
  }
191
242
  /**
192
- * Time Complexity: O(1)
193
- * Space Complexity: O(1)
194
- *
195
- * The `shift()` function removes and returns the value of the first element in a linked list.
196
- * @returns The value of the removed node.
243
+ * Remove and return the head element.
244
+ * @remarks Time O(1), Space O(1)
245
+ * @returns Removed element or undefined.
197
246
  */
198
247
  shift() {
199
248
  if (!this.head)
200
249
  return undefined;
201
- const removedNode = this.head;
250
+ const removed = this.head;
202
251
  this._head = this.head.next;
252
+ if (!this._head)
253
+ this._tail = undefined;
203
254
  this._length--;
204
- return removedNode.value;
255
+ return removed.value;
205
256
  }
206
257
  /**
207
- * Time Complexity: O(1)
208
- * Space Complexity: O(1)
209
- *
210
- * The unshift function adds a new element or node to the beginning of a singly linked list in
211
- * TypeScript.
212
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the
213
- * `unshift` method can be either an element of type `E` or a `SinglyLinkedListNode` containing an
214
- * element of type `E`.
215
- * @returns The `unshift` method is returning a boolean value, specifically `true`.
258
+ * Prepend an element/node to the head.
259
+ * @remarks Time O(1), Space O(1)
260
+ * @param elementOrNode - Element or node to prepend.
261
+ * @returns True when prepended.
216
262
  */
217
263
  unshift(elementOrNode) {
218
264
  const newNode = this._ensureNode(elementOrNode);
219
265
  if (!this.head) {
220
- this._head = newNode;
221
- this._tail = newNode;
266
+ this._head = this._tail = newNode;
222
267
  }
223
268
  else {
224
269
  newNode.next = this.head;
@@ -228,63 +273,42 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
228
273
  return true;
229
274
  }
230
275
  /**
231
- * Time Complexity: O(k)
232
- * Space Complexity: O(k)
233
- *
234
- * The function `pushMany` iterates over elements and pushes them into a data structure, applying a
235
- * transformation function if provided.
236
- * @param {Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>} elements - The `elements`
237
- * parameter in the `pushMany` function can accept an iterable containing elements of type `E`, `R`,
238
- * or `SinglyLinkedListNode<E>`.
239
- * @returns The `pushMany` function returns an array of boolean values indicating whether each
240
- * element was successfully pushed into the data structure.
276
+ * Append a sequence of elements/nodes.
277
+ * @remarks Time O(N), Space O(1)
278
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
279
+ * @returns Array of per-element success flags.
241
280
  */
242
281
  pushMany(elements) {
243
282
  const ans = [];
244
283
  for (const el of elements) {
245
- if (this.toElementFn) {
284
+ if (this.toElementFn)
246
285
  ans.push(this.push(this.toElementFn(el)));
247
- continue;
248
- }
249
- ans.push(this.push(el));
286
+ else
287
+ ans.push(this.push(el));
250
288
  }
251
289
  return ans;
252
290
  }
253
291
  /**
254
- * Time Complexity: O(k)
255
- * Space Complexity: O(k)
256
- *
257
- * The function `unshiftMany` iterates over elements and adds them to a data structure, optionally
258
- * converting them using a provided function.
259
- * @param {Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>} elements - The `elements`
260
- * parameter in the `unshiftMany` function can accept an iterable containing elements of type `E`,
261
- * `R`, or `SinglyLinkedListNode<E>`. The function iterates over each element in the iterable and
262
- * performs an `unshift` operation on the linked list for each
263
- * @returns The `unshiftMany` function is returning an array of boolean values, where each value
264
- * represents the result of calling the `unshift` method on the current instance of the class.
292
+ * Prepend a sequence of elements/nodes.
293
+ * @remarks Time O(N), Space O(1)
294
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
295
+ * @returns Array of per-element success flags.
265
296
  */
266
297
  unshiftMany(elements) {
267
298
  const ans = [];
268
299
  for (const el of elements) {
269
- if (this.toElementFn) {
300
+ if (this.toElementFn)
270
301
  ans.push(this.unshift(this.toElementFn(el)));
271
- continue;
272
- }
273
- ans.push(this.unshift(el));
302
+ else
303
+ ans.push(this.unshift(el));
274
304
  }
275
305
  return ans;
276
306
  }
277
307
  /**
278
- * Time Complexity: O(n)
279
- * Space Complexity: O(1)
280
- *
281
- * This function searches for a specific element in a singly linked list based on a given node or
282
- * predicate.
283
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
284
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `get` method can be one of
285
- * the following types:
286
- * @returns The `get` method returns the value of the first node in the singly linked list that
287
- * satisfies the provided predicate function. If no such node is found, it returns `undefined`.
308
+ * Find the first value matching a predicate (by node).
309
+ * @remarks Time O(N), Space O(1)
310
+ * @param elementNodeOrPredicate - Element, node, or node predicate to match.
311
+ * @returns Matched value or undefined.
288
312
  */
289
313
  search(elementNodeOrPredicate) {
290
314
  const predicate = this._ensurePredicate(elementNodeOrPredicate);
@@ -297,97 +321,67 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
297
321
  return undefined;
298
322
  }
299
323
  /**
300
- * Time Complexity: O(n)
301
- * Space Complexity: O(1)
302
- *
303
- * The function `at` returns the value at a specified index in a linked list, or undefined if the index is out of range.
304
- * @param {number} index - The index parameter is a number that represents the position of the element we want to
305
- * retrieve from the list.
306
- * @returns The method `at(index: number): E | undefined` returns the value at the specified index in the linked list, or
307
- * `undefined` if the index is out of bounds.
324
+ * Get the element at a given index.
325
+ * @remarks Time O(N), Space O(1)
326
+ * @param index - Zero-based index.
327
+ * @returns Element or undefined.
308
328
  */
309
329
  at(index) {
310
330
  if (index < 0 || index >= this._length)
311
331
  return undefined;
312
332
  let current = this.head;
313
- for (let i = 0; i < index; i++) {
333
+ for (let i = 0; i < index; i++)
314
334
  current = current.next;
315
- }
316
335
  return current.value;
317
336
  }
318
337
  /**
319
- * Time Complexity: O(1)
320
- * Space Complexity: O(1)
321
- *
322
- * The function `isNode` in TypeScript checks if the input is an instance of `SinglyLinkedListNode`.
323
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
324
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `isNode` function can be
325
- * one of the following types:
326
- * @returns The `isNode` function is checking if the `elementNodeOrPredicate` parameter is an
327
- * instance of `SinglyLinkedListNode<E>`. If it is, the function returns `true`, indicating that the
328
- * parameter is a `SinglyLinkedListNode<E>`. If it is not an instance of `SinglyLinkedListNode<E>`,
329
- * the function returns `false`.
338
+ * Type guard: check whether the input is a SinglyLinkedListNode.
339
+ * @remarks Time O(1), Space O(1)
340
+ * @param elementNodeOrPredicate - Element, node, or predicate.
341
+ * @returns True if the value is a SinglyLinkedListNode.
330
342
  */
331
343
  isNode(elementNodeOrPredicate) {
332
344
  return elementNodeOrPredicate instanceof SinglyLinkedListNode;
333
345
  }
334
346
  /**
335
- * Time Complexity: O(n)
336
- * Space Complexity: O(1)
337
- *
338
- * The function `getNodeAt` returns the node at a given index in a singly linked list.
339
- * @param {number} index - The `index` parameter is a number that represents the position of the node we want to
340
- * retrieve from the linked list. It indicates the zero-based index of the node we want to access.
341
- * @returns The method `getNodeAt(index: number)` returns a `SinglyLinkedListNode<E>` object if the node at the
342
- * specified index exists, or `undefined` if the index is out of bounds.
347
+ * Get the node reference at a given index.
348
+ * @remarks Time O(N), Space O(1)
349
+ * @param index - Zero-based index.
350
+ * @returns Node or undefined.
343
351
  */
344
352
  getNodeAt(index) {
353
+ if (index < 0 || index >= this._length)
354
+ return undefined;
345
355
  let current = this.head;
346
- for (let i = 0; i < index; i++) {
356
+ for (let i = 0; i < index; i++)
347
357
  current = current.next;
348
- }
349
358
  return current;
350
359
  }
351
360
  /**
352
- * Time Complexity: O(n)
353
- * Space Complexity: O(1)
354
- *
355
- * The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element.
356
- * @param {number} index - The index parameter represents the position of the element that needs to be deleted in the
357
- * data structure. It is of type number.
358
- * @returns The method `deleteAt` returns the value of the node that was deleted, or `undefined` if the index is out of
359
- * bounds.
361
+ * Delete the element at an index.
362
+ * @remarks Time O(N), Space O(1)
363
+ * @param index - Zero-based index.
364
+ * @returns Removed element or undefined.
360
365
  */
361
366
  deleteAt(index) {
362
367
  if (index < 0 || index >= this._length)
363
- return;
364
- let deleted;
365
- if (index === 0) {
366
- deleted = this.first;
367
- this.shift();
368
- return deleted;
369
- }
368
+ return undefined;
369
+ if (index === 0)
370
+ return this.shift();
370
371
  const targetNode = this.getNodeAt(index);
371
372
  const prevNode = this._getPrevNode(targetNode);
372
- if (prevNode && targetNode) {
373
- deleted = targetNode.value;
374
- prevNode.next = targetNode.next;
375
- if (targetNode === this.tail)
376
- this._tail = prevNode;
377
- this._length--;
378
- return deleted;
379
- }
380
- return;
373
+ const value = targetNode.value;
374
+ prevNode.next = targetNode.next;
375
+ if (targetNode === this.tail)
376
+ this._tail = prevNode;
377
+ this._length--;
378
+ return value;
381
379
  }
382
380
  /**
383
- * Time Complexity: O(n)
384
- * Space Complexity: O(1)
385
- *
386
- * The delete function removes a node with a specific value from a singly linked list.
387
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter can accept either a value of type `E`
388
- * or a `SinglyLinkedListNode<E>` object.
389
- * @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and
390
- * successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
381
+ * Delete the first match by value/node.
382
+ * @remarks Time O(N), Space O(1)
383
+ * @param [elementOrNode] - Element or node to remove; if omitted/undefined, nothing happens.
384
+ * @returns True if removed.
391
385
  */
392
386
  delete(elementOrNode) {
393
387
  if (elementOrNode === undefined || !this.head)
@@ -397,7 +391,6 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
397
391
  return false;
398
392
  const prevNode = this._getPrevNode(node);
399
393
  if (!prevNode) {
400
- // The node is the head
401
394
  this._head = node.next;
402
395
  if (node === this.tail)
403
396
  this._tail = undefined;
@@ -411,31 +404,19 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
411
404
  return true;
412
405
  }
413
406
  /**
414
- * Time Complexity: O(n)
415
- * Space Complexity: O(1)
416
- *
417
- * The `addAt` function inserts a new element or node at a specified index in a singly linked list.
418
- * @param {number} index - The `index` parameter represents the position at which you want to add a
419
- * new element or node in the linked list. It is a number that indicates the index where the new
420
- * element or node should be inserted.
421
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
422
- * `addAt` method can be either a value of type `E` or a `SinglyLinkedListNode<E>` object. This
423
- * parameter represents the element or node that you want to add to the linked list at the specified
424
- * index.
425
- * @returns The `addAt` method returns a boolean value - `true` if the element or node was
426
- * successfully added at the specified index, and `false` if the index is out of bounds.
407
+ * Insert a new element/node at an index, shifting following nodes.
408
+ * @remarks Time O(N), Space O(1)
409
+ * @param index - Zero-based index.
410
+ * @param newElementOrNode - Element or node to insert.
411
+ * @returns True if inserted.
427
412
  */
428
413
  addAt(index, newElementOrNode) {
429
414
  if (index < 0 || index > this._length)
430
415
  return false;
431
- if (index === 0) {
432
- this.unshift(newElementOrNode);
433
- return true;
434
- }
435
- if (index === this._length) {
436
- this.push(newElementOrNode);
437
- return true;
438
- }
416
+ if (index === 0)
417
+ return this.unshift(newElementOrNode);
418
+ if (index === this._length)
419
+ return this.push(newElementOrNode);
439
420
  const newNode = this._ensureNode(newElementOrNode);
440
421
  const prevNode = this.getNodeAt(index - 1);
441
422
  newNode.next = prevNode.next;
@@ -444,43 +425,31 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
444
425
  return true;
445
426
  }
446
427
  /**
447
- * Time Complexity: O(n)
448
- * Space Complexity: O(1)
449
- *
450
- * The function setAt(index, value) updates the value at a specified index in a data structure if the
451
- * index exists.
452
- * @param {number} index - The `index` parameter in the `setAt` method refers to the position in the
453
- * data structure where you want to set a new value.
454
- * @param {E} value - The `value` parameter in the `setAt` method represents the new value that you
455
- * want to set at the specified index in the data structure.
456
- * @returns The `setAt` method returns a boolean value - `true` if the value at the specified index
457
- * is successfully updated, and `false` if the index is out of bounds (i.e., the node at that index
458
- * does not exist).
428
+ * Set the element value at an index.
429
+ * @remarks Time O(N), Space O(1)
430
+ * @param index - Zero-based index.
431
+ * @param value - New value.
432
+ * @returns True if updated.
459
433
  */
460
434
  setAt(index, value) {
461
435
  const node = this.getNodeAt(index);
462
- if (node) {
463
- node.value = value;
464
- return true;
465
- }
466
- return false;
436
+ if (!node)
437
+ return false;
438
+ node.value = value;
439
+ return true;
467
440
  }
468
441
  /**
469
- * Time Complexity: O(1)
470
- * Space Complexity: O(1)
471
- *
472
- * The function checks if the length of a data structure is equal to zero and returns a boolean value indicating
473
- * whether it is empty or not.
474
- * @returns A boolean value indicating whether the length of the object is equal to 0.
442
+ * Check whether the list is empty.
443
+ * @remarks Time O(1), Space O(1)
444
+ * @returns True if length is 0.
475
445
  */
476
446
  isEmpty() {
477
447
  return this._length === 0;
478
448
  }
479
449
  /**
480
- * Time Complexity: O(1)
481
- * Space Complexity: O(1)
482
- *
483
- * The `clear` function resets the linked list by setting the head, tail, and length to undefined and 0 respectively.
450
+ * Remove all nodes and reset length.
451
+ * @remarks Time O(N), Space O(1)
452
+ * @returns void
484
453
  */
485
454
  clear() {
486
455
  this._head = undefined;
@@ -488,18 +457,16 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
488
457
  this._length = 0;
489
458
  }
490
459
  /**
491
- * Time Complexity: O(n)
492
- * Space Complexity: O(1)
493
- *
494
- * The `reverse` function reverses the order of the nodes in a singly linked list.
495
- * @returns The reverse() method does not return anything. It has a return type of void.
460
+ * Reverse the list in place.
461
+ * @remarks Time O(N), Space O(1)
462
+ * @returns This list.
496
463
  */
497
464
  reverse() {
498
465
  if (!this.head || this.head === this.tail)
499
466
  return this;
500
- let prev = undefined;
467
+ let prev;
501
468
  let current = this.head;
502
- let next = undefined;
469
+ let next;
503
470
  while (current) {
504
471
  next = current.next;
505
472
  current.next = prev;
@@ -510,17 +477,10 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
510
477
  return this;
511
478
  }
512
479
  /**
513
- * Time Complexity: O(n)
514
- * Space Complexity: O(1)
515
- *
516
- * The function `getNode` in TypeScript searches for a node in a singly linked list based on a given
517
- * element, node, or predicate.
518
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean) | undefined} elementNodeOrPredicate
519
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `getNode` method can be one
520
- * of the following types:
521
- * @returns The `getNode` method returns either a `SinglyLinkedListNode<E>` if a matching node is
522
- * found based on the provided predicate, or it returns `undefined` if no matching node is found or
523
- * if the input parameter is `undefined`.
480
+ * Find a node by value, reference, or predicate.
481
+ * @remarks Time O(N), Space O(1)
482
+ * @param [elementNodeOrPredicate] - Element, node, or node predicate to match.
483
+ * @returns Matching node or undefined.
524
484
  */
525
485
  getNode(elementNodeOrPredicate) {
526
486
  if (elementNodeOrPredicate === undefined)
@@ -530,28 +490,18 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
530
490
  const predicate = this._ensurePredicate(elementNodeOrPredicate);
531
491
  let current = this.head;
532
492
  while (current) {
533
- if (predicate(current)) {
493
+ if (predicate(current))
534
494
  return current;
535
- }
536
495
  current = current.next;
537
496
  }
538
497
  return undefined;
539
498
  }
540
499
  /**
541
- * Time Complexity: O(n)
542
- * Space Complexity: O(1)
543
- *
544
- * The function `addBefore` in TypeScript adds a new element or node before an existing element or
545
- * node in a singly linked list.
546
- * @param {E | SinglyLinkedListNode<E>} existingElementOrNode - existingElementOrNode represents the
547
- * element or node in the linked list before which you want to add a new element or node.
548
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
549
- * `addBefore` method represents the element or node that you want to insert before the existing
550
- * element or node in the linked list. This new element can be of type `E` or a
551
- * `SinglyLinkedListNode<E>`.
552
- * @returns The `addBefore` method returns a boolean value - `true` if the new element or node was
553
- * successfully added before the existing element or node, and `false` if the operation was
554
- * unsuccessful.
500
+ * Insert a new element/node before an existing one.
501
+ * @remarks Time O(N), Space O(1)
502
+ * @param existingElementOrNode - Existing element or node.
503
+ * @param newElementOrNode - Element or node to insert.
504
+ * @returns True if inserted.
555
505
  */
556
506
  addBefore(existingElementOrNode, newElementOrNode) {
557
507
  const existingNode = this.getNode(existingElementOrNode);
@@ -560,8 +510,11 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
560
510
  const prevNode = this._getPrevNode(existingNode);
561
511
  const newNode = this._ensureNode(newElementOrNode);
562
512
  if (!prevNode) {
563
- // Add at the head
564
- this.unshift(newNode);
513
+ newNode.next = this._head;
514
+ this._head = newNode;
515
+ if (!this._tail)
516
+ this._tail = newNode;
517
+ this._length++;
565
518
  }
566
519
  else {
567
520
  prevNode.next = newNode;
@@ -571,299 +524,327 @@ class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
571
524
  return true;
572
525
  }
573
526
  /**
574
- * Time Complexity: O(n)
575
- * Space Complexity: O(1)
576
- *
577
- * The `addAfter` function in TypeScript adds a new element or node after an existing element or node
578
- * in a singly linked list.
579
- * @param {E | SinglyLinkedListNode<E>} existingElementOrNode - existingElementOrNode can be either
580
- * an element of type E or a SinglyLinkedListNode of type E.
581
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
582
- * `addAfter` method represents the element or node that you want to add after the existing element
583
- * or node in a singly linked list. This parameter can be either the value of the new element or a
584
- * reference to a `SinglyLinkedListNode` containing
585
- * @returns The `addAfter` method returns a boolean value - `true` if the new element or node was
586
- * successfully added after the existing element or node, and `false` if the existing element or node
587
- * was not found.
527
+ * Insert a new element/node after an existing one.
528
+ * @remarks Time O(N), Space O(1)
529
+ * @param existingElementOrNode - Existing element or node.
530
+ * @param newElementOrNode - Element or node to insert.
531
+ * @returns True if inserted.
588
532
  */
589
533
  addAfter(existingElementOrNode, newElementOrNode) {
590
534
  const existingNode = this.getNode(existingElementOrNode);
591
- if (existingNode) {
592
- const newNode = this._ensureNode(newElementOrNode);
593
- newNode.next = existingNode.next;
594
- existingNode.next = newNode;
595
- if (existingNode === this.tail) {
596
- this._tail = newNode;
597
- }
598
- this._length++;
599
- return true;
600
- }
601
- return false;
535
+ if (!existingNode)
536
+ return false;
537
+ const newNode = this._ensureNode(newElementOrNode);
538
+ newNode.next = existingNode.next;
539
+ existingNode.next = newNode;
540
+ if (existingNode === this.tail)
541
+ this._tail = newNode;
542
+ this._length++;
543
+ return true;
602
544
  }
603
545
  /**
604
- * Time Complexity: O(n)
605
- * Space Complexity: O(1)
606
- *
607
- * The function `splice` in TypeScript overrides the default behavior to remove and insert elements
608
- * in a singly linked list while handling boundary cases.
609
- * @param {number} start - The `start` parameter in the `splice` method indicates the index at which
610
- * to start modifying the list. It specifies the position where elements will be added or removed.
611
- * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the
612
- * number of elements to remove from the array starting at the specified `start` index. If
613
- * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new
614
- * elements can still be inserted at
615
- * @param {E[]} items - The `items` parameter in the `splice` method represents the elements to be
616
- * inserted into the list at the specified `start` index. These elements will be inserted in place of
617
- * the elements that are removed from the list. The `splice` method allows you to add new elements to
618
- * the list while
619
- * @returns The `splice` method is returning a `SinglyLinkedList` containing the elements that were
620
- * removed from the original list during the splice operation.
546
+ * Remove and/or insert elements at a position (array-like behavior).
547
+ * @remarks Time O(N + M), Space O(M)
548
+ * @param start - Start index (clamped to [0, length]).
549
+ * @param [deleteCount] - Number of elements to remove (default 0).
550
+ * @param [items] - Elements to insert after `start`.
551
+ * @returns A new list containing the removed elements (typed as `this`).
621
552
  */
622
553
  splice(start, deleteCount = 0, ...items) {
623
- const removedList = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
624
- // If `start` is out of range, perform boundary processing
625
554
  start = Math.max(0, Math.min(start, this.length));
626
555
  deleteCount = Math.max(0, deleteCount);
627
- // Find the predecessor node of `start`
556
+ const removedList = this._createInstance();
628
557
  const prevNode = start === 0 ? undefined : this.getNodeAt(start - 1);
629
- const startNode = prevNode ? prevNode.next : this.head;
630
- let current = startNode;
631
- for (let i = 0; i < deleteCount && current; i++) {
632
- removedList.push(current.value);
633
- current = current.next;
634
- }
635
- const nextNode = current;
636
- let lastInsertedNode = undefined;
637
- for (const item of items) {
638
- const newNode = this._ensureNode(item);
639
- if (!lastInsertedNode) {
640
- if (prevNode) {
641
- prevNode.next = newNode;
642
- }
643
- else {
644
- this._head = newNode;
645
- }
646
- }
647
- else {
648
- lastInsertedNode.next = newNode;
649
- }
650
- lastInsertedNode = newNode;
558
+ let cur = prevNode ? prevNode.next : this.head;
559
+ let removedCount = 0;
560
+ while (removedCount < deleteCount && cur) {
561
+ removedList.push(cur.value);
562
+ cur = cur.next;
563
+ removedCount++;
651
564
  }
652
- // Connect new node to `nextNode`
653
- if (lastInsertedNode) {
654
- lastInsertedNode.next = nextNode;
565
+ const afterNode = cur;
566
+ if (prevNode) {
567
+ prevNode.next = afterNode;
655
568
  }
656
- else if (prevNode) {
657
- prevNode.next = nextNode;
658
- }
659
- // Update tail node and length
660
- if (!nextNode) {
661
- this._tail = lastInsertedNode || prevNode;
569
+ else {
570
+ this._head = afterNode;
571
+ }
572
+ if (!afterNode)
573
+ this._tail = prevNode;
574
+ if (items.length > 0) {
575
+ let firstInserted;
576
+ let lastInserted;
577
+ for (const it of items) {
578
+ const node = this._ensureNode(it);
579
+ if (!firstInserted)
580
+ firstInserted = node;
581
+ if (lastInserted)
582
+ lastInserted.next = node;
583
+ lastInserted = node;
584
+ }
585
+ if (prevNode)
586
+ prevNode.next = firstInserted;
587
+ else
588
+ this._head = firstInserted;
589
+ lastInserted.next = afterNode;
590
+ if (!afterNode)
591
+ this._tail = lastInserted;
592
+ }
593
+ this._length += items.length - removedCount;
594
+ if (this._length === 0) {
595
+ this._head = undefined;
596
+ this._tail = undefined;
662
597
  }
663
- this._length += items.length - removedList.length;
664
598
  return removedList;
665
599
  }
666
600
  /**
667
- * Time Complexity: O(n)
668
- * Space Complexity: O(1)
669
- *
670
- * The function `countOccurrences` iterates through a singly linked list and counts the occurrences
671
- * of a specified element or nodes that satisfy a given predicate.
672
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementOrNode
673
- * - The `elementOrNode` parameter in the `countOccurrences` method can accept three types of values:
674
- * @returns The `countOccurrences` method returns the number of occurrences of the specified element,
675
- * node, or predicate function in the singly linked list.
601
+ * Count how many nodes match a value/node/predicate.
602
+ * @remarks Time O(N), Space O(1)
603
+ * @param elementOrNode - Element, node, or node predicate to match.
604
+ * @returns Number of matches in the list.
676
605
  */
677
606
  countOccurrences(elementOrNode) {
678
- const predicate = this._ensurePredicate(elementOrNode);
607
+ const predicate = elementOrPredicate(elementOrNode, this._equals);
679
608
  let count = 0;
680
609
  let current = this.head;
681
610
  while (current) {
682
- if (predicate(current)) {
611
+ if (predicate(current))
683
612
  count++;
684
- }
685
613
  current = current.next;
686
614
  }
687
615
  return count;
688
616
  }
689
617
  /**
690
- * Time Complexity: O(n)
691
- * Space Complexity: O(n)
692
- *
693
- * The `clone` function returns a new instance of the `SinglyLinkedList` class with the same values
694
- * as the original list.
695
- * @returns The `clone()` method is returning a new instance of the `SinglyLinkedList` class, which
696
- * is a clone of the original list.
618
+ * Set the equality comparator used to compare values.
619
+ * @remarks Time O(1), Space O(1)
620
+ * @param equals - Equality predicate (a, b) → boolean.
621
+ * @returns This list.
697
622
  */
698
- clone() {
699
- return new SinglyLinkedList(this, { toElementFn: this.toElementFn, maxLen: this._maxLen });
700
- }
701
- /**
702
- * Time Complexity: O(n)
703
- * Space Complexity: O(n)
704
- *
705
- * The `filter` function creates a new SinglyLinkedList by iterating over the elements of the current
706
- * list and applying a callback function to each element to determine if it should be included in the
707
- * filtered list.
708
- * @param callback - The callback parameter is a function that will be called for each element in the
709
- * list. It takes three arguments: the current element, the index of the current element, and the
710
- * list itself. The callback function should return a boolean value indicating whether the current
711
- * element should be included in the filtered list or not
712
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
713
- * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be
714
- * passed as the `this` value to the `callback` function. If `thisArg` is
715
- * @returns The `filter` method is returning a new `SinglyLinkedList` object that contains the
716
- * elements that pass the filter condition specified by the `callback` function.
623
+ setEquality(equals) {
624
+ this._equals = equals;
625
+ return this;
626
+ }
627
+ /**
628
+ * Delete the first node whose value matches a predicate.
629
+ * @remarks Time O(N), Space O(1)
630
+ * @param predicate - Predicate (value, index, list) boolean to decide deletion.
631
+ * @returns True if a node was removed.
717
632
  */
718
- filter(callback, thisArg) {
719
- const filteredList = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
720
- let index = 0;
721
- for (const current of this) {
722
- if (callback.call(thisArg, current, index, this)) {
723
- filteredList.push(current);
633
+ deleteWhere(predicate) {
634
+ let prev;
635
+ let current = this.head;
636
+ let i = 0;
637
+ while (current) {
638
+ if (predicate(current.value, i++, this)) {
639
+ if (!prev) {
640
+ this._head = current.next;
641
+ if (current === this._tail)
642
+ this._tail = undefined;
643
+ }
644
+ else {
645
+ prev.next = current.next;
646
+ if (current === this._tail)
647
+ this._tail = prev;
648
+ }
649
+ this._length--;
650
+ return true;
724
651
  }
725
- index++;
726
- }
727
- return filteredList;
728
- }
729
- /**
730
- * Time Complexity: O(n)
731
- * Space Complexity: O(n)
732
- *
733
- * The `map` function takes a callback function and returns a new SinglyLinkedList with the results
734
- * of applying the callback to each element in the original list.
735
- * @param callback - The `callback` parameter is a function that will be called for each element in
736
- * the original list. It takes three arguments: `current` (the current element being processed),
737
- * `index` (the index of the current element), and `this` (the original list). It should return a
738
- * value
739
- * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to
740
- * convert the raw element (`RR`) to the desired element type (`T`). It takes the raw element as
741
- * input and returns the converted element. If this parameter is not provided, the raw element will
742
- * be used as is.
743
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
744
- * specify the value of `this` within the callback function. It is used to set the context or scope
745
- * in which the callback function will be executed. If `thisArg` is provided, it will be used as the
746
- * value of
747
- * @returns a new instance of the `SinglyLinkedList` class with the mapped elements.
748
- */
749
- map(callback, toElementFn, thisArg) {
750
- const mappedList = new SinglyLinkedList([], { toElementFn, maxLen: this._maxLen });
751
- let index = 0;
752
- for (const current of this) {
753
- mappedList.push(callback.call(thisArg, current, index, this));
754
- index++;
652
+ prev = current;
653
+ current = current.next;
755
654
  }
756
- return mappedList;
655
+ return false;
757
656
  }
758
657
  /**
759
- * The function `_createInstance` returns a new instance of `SinglyLinkedList` with the specified
760
- * options.
761
- * @param [options] - The `options` parameter in the `_createInstance` method is of type
762
- * `SinglyLinkedListOptions<E, R>`, which is used to configure the behavior of the `SinglyLinkedList`
763
- * instance being created. It is an optional parameter, meaning it can be omitted when calling the
764
- * method.
765
- * @returns An instance of the `SinglyLinkedList` class with an empty array and the provided options
766
- * is being returned.
658
+ * Deep clone this list (values are copied by reference).
659
+ * @remarks Time O(N), Space O(N)
660
+ * @returns A new list with the same element sequence.
767
661
  */
768
- _createInstance(options) {
769
- return new SinglyLinkedList([], options);
662
+ clone() {
663
+ const out = this._createInstance();
664
+ for (const v of this)
665
+ out.push(v);
666
+ return out;
770
667
  }
771
668
  /**
772
- * The function `_getIterator` returns an iterable iterator that yields the values of a linked list.
669
+ * Filter values into a new list of the same class.
670
+ * @remarks Time O(N), Space O(N)
671
+ * @param callback - Predicate (value, index, list) → boolean to keep value.
672
+ * @param [thisArg] - Value for `this` inside the callback.
673
+ * @returns A new list with kept values.
773
674
  */
774
- *_getIterator() {
775
- let current = this.head;
776
- while (current) {
777
- yield current.value;
778
- current = current.next;
779
- }
675
+ filter(callback, thisArg) {
676
+ const out = this._createInstance();
677
+ let index = 0;
678
+ for (const value of this)
679
+ if (callback.call(thisArg, value, index++, this))
680
+ out.push(value);
681
+ return out;
780
682
  }
781
683
  /**
782
- * The function returns an iterator that iterates over the elements of a collection in reverse order.
684
+ * Map values into a new list of the same class.
685
+ * @remarks Time O(N), Space O(N)
686
+ * @param callback - Mapping function (value, index, list) → newValue.
687
+ * @param [thisArg] - Value for `this` inside the callback.
688
+ * @returns A new list with mapped values.
783
689
  */
784
- *_getReverseIterator() {
785
- const reversedArr = [...this].reverse();
786
- for (const item of reversedArr) {
787
- yield item;
690
+ mapSame(callback, thisArg) {
691
+ const out = this._createInstance();
692
+ let index = 0;
693
+ for (const value of this) {
694
+ const mv = thisArg === undefined ? callback(value, index++, this) : callback.call(thisArg, value, index++, this);
695
+ out.push(mv);
788
696
  }
697
+ return out;
789
698
  }
790
699
  /**
791
- * The function `_getNodeIterator` returns an iterator that iterates over the nodes of a singly
792
- * linked list.
700
+ * Map values into a new list (possibly different element type).
701
+ * @remarks Time O(N), Space O(N)
702
+ * @template EM
703
+ * @template RM
704
+ * @param callback - Mapping function (value, index, list) → newElement.
705
+ * @param [options] - Options for the output list (e.g., maxLen, toElementFn).
706
+ * @param [thisArg] - Value for `this` inside the callback.
707
+ * @returns A new SinglyLinkedList with mapped values.
793
708
  */
794
- *_getNodeIterator() {
795
- let current = this.head;
796
- while (current) {
797
- yield current;
798
- current = current.next;
799
- }
709
+ map(callback, options, thisArg) {
710
+ const out = this._createLike([], Object.assign(Object.assign({}, (options !== null && options !== void 0 ? options : {})), { maxLen: this._maxLen }));
711
+ let index = 0;
712
+ for (const value of this)
713
+ out.push(callback.call(thisArg, value, index++, this));
714
+ return out;
715
+ }
716
+ /**
717
+ * (Protected) Create a node from a value.
718
+ * @remarks Time O(1), Space O(1)
719
+ * @param value - Value to wrap in a node.
720
+ * @returns A new SinglyLinkedListNode instance.
721
+ */
722
+ _createNode(value) {
723
+ return new SinglyLinkedListNode(value);
800
724
  }
801
- // protected *_getReverseNodeIterator(): IterableIterator<SinglyLinkedListNode<E>> {
802
- // const reversedArr = [...this._getNodeIterator()].reverse();
803
- //
804
- // for (const item of reversedArr) {
805
- // yield item;
806
- // }
807
- // }
808
- /**
809
- * The _isPredicate function in TypeScript checks if the input is a function that takes a
810
- * SinglyLinkedListNode as an argument and returns a boolean.
811
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
812
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following types:
813
- * @returns The _isPredicate method is returning a boolean value based on whether the
814
- * elementNodeOrPredicate parameter is a function or not. If the elementNodeOrPredicate is a
815
- * function, the method will return true, indicating that it is a predicate function. If it is not a
816
- * function, the method will return false.
725
+ /**
726
+ * (Protected) Check if input is a node predicate function.
727
+ * @remarks Time O(1), Space O(1)
728
+ * @param elementNodeOrPredicate - Element, node, or node predicate.
729
+ * @returns True if input is a predicate function.
817
730
  */
818
731
  _isPredicate(elementNodeOrPredicate) {
819
732
  return typeof elementNodeOrPredicate === 'function';
820
733
  }
821
734
  /**
822
- * The function `_ensureNode` ensures that the input is a valid node and returns it, creating a new
823
- * node if necessary.
824
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter can be either
825
- * an element of type `E` or a `SinglyLinkedListNode` containing an element of type `E`.
826
- * @returns A SinglyLinkedListNode<E> object is being returned.
735
+ * (Protected) Normalize input into a node instance.
736
+ * @remarks Time O(1), Space O(1)
737
+ * @param elementOrNode - Element or node.
738
+ * @returns A SinglyLinkedListNode for the provided input.
827
739
  */
828
740
  _ensureNode(elementOrNode) {
829
741
  if (this.isNode(elementOrNode))
830
742
  return elementOrNode;
831
- return new SinglyLinkedListNode(elementOrNode);
743
+ return this._createNode(elementOrNode);
832
744
  }
833
745
  /**
834
- * The function `_ensurePredicate` in TypeScript ensures that the input is either a node, a predicate
835
- * function, or a value to compare with the node's value.
836
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
837
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following types:
838
- * @returns A function is being returned. If the input `elementNodeOrPredicate` is already a node, a
839
- * function is returned that checks if a given node is equal to the input node. If the input is a
840
- * predicate function, it is returned as is. If the input is neither a node nor a predicate function,
841
- * a function is returned that checks if a given node's value is equal to the input
746
+ * (Protected) Normalize input into a node predicate.
747
+ * @remarks Time O(1), Space O(1)
748
+ * @param elementNodeOrPredicate - Element, node, or predicate.
749
+ * @returns A predicate taking a node and returning true/false.
842
750
  */
843
751
  _ensurePredicate(elementNodeOrPredicate) {
844
752
  if (this.isNode(elementNodeOrPredicate))
845
753
  return (node) => node === elementNodeOrPredicate;
846
754
  if (this._isPredicate(elementNodeOrPredicate))
847
755
  return elementNodeOrPredicate;
848
- return (node) => node.value === elementNodeOrPredicate;
756
+ const value = elementNodeOrPredicate;
757
+ return (node) => this._equals(node.value, value);
849
758
  }
850
759
  /**
851
- * The function `_getPrevNode` returns the node before a given node in a singly linked list.
852
- * @param node - The `node` parameter in the `_getPrevNode` method is a reference to a node in a
853
- * singly linked list. The method is used to find the node that comes before the given node in the
854
- * linked list.
855
- * @returns The `_getPrevNode` method returns either the previous node of the input node in a singly
856
- * linked list or `undefined` if the input node is the head of the list or if the input node is not
857
- * found in the list.
760
+ * (Protected) Get the previous node of a given node.
761
+ * @remarks Time O(N), Space O(1)
762
+ * @param node - A node in the list.
763
+ * @returns Previous node or undefined.
858
764
  */
859
765
  _getPrevNode(node) {
860
766
  if (!this.head || this.head === node)
861
767
  return undefined;
862
768
  let current = this.head;
863
- while (current.next && current.next !== node) {
769
+ while (current.next && current.next !== node)
864
770
  current = current.next;
865
- }
866
771
  return current.next === node ? current : undefined;
867
772
  }
773
+ /**
774
+ * (Protected) Iterate values from head to tail.
775
+ * @remarks Time O(N), Space O(1)
776
+ * @returns Iterator of values (E).
777
+ */
778
+ *_getIterator() {
779
+ let current = this.head;
780
+ while (current) {
781
+ yield current.value;
782
+ current = current.next;
783
+ }
784
+ }
785
+ /**
786
+ * (Protected) Iterate values from tail to head.
787
+ * @remarks Time O(N), Space O(N)
788
+ * @returns Iterator of values (E).
789
+ */
790
+ *_getReverseIterator() {
791
+ const reversedArr = [...this].reverse();
792
+ for (const item of reversedArr)
793
+ yield item;
794
+ }
795
+ /**
796
+ * (Protected) Iterate nodes from head to tail.
797
+ * @remarks Time O(N), Space O(1)
798
+ * @returns Iterator of nodes.
799
+ */
800
+ *_getNodeIterator() {
801
+ let current = this.head;
802
+ while (current) {
803
+ yield current;
804
+ current = current.next;
805
+ }
806
+ }
807
+ /**
808
+ * (Protected) Create an empty instance of the same concrete class.
809
+ * @remarks Time O(1), Space O(1)
810
+ * @param [options] - Options forwarded to the constructor.
811
+ * @returns An empty like-kind list instance.
812
+ */
813
+ _createInstance(options) {
814
+ const Ctor = this.constructor;
815
+ return new Ctor([], options);
816
+ }
817
+ /**
818
+ * (Protected) Create a like-kind instance and seed it from an iterable.
819
+ * @remarks Time O(N), Space O(N)
820
+ * @template EM
821
+ * @template RM
822
+ * @param [elements] - Iterable used to seed the new list.
823
+ * @param [options] - Options forwarded to the constructor.
824
+ * @returns A like-kind SinglyLinkedList instance.
825
+ */
826
+ _createLike(elements = [], options) {
827
+ const Ctor = this.constructor;
828
+ return new Ctor(elements, options);
829
+ }
830
+ /**
831
+ * (Protected) Spawn an empty like-kind list instance.
832
+ * @remarks Time O(1), Space O(1)
833
+ * @template EM
834
+ * @template RM
835
+ * @param [options] - Options forwarded to the constructor.
836
+ * @returns An empty like-kind SinglyLinkedList instance.
837
+ */
838
+ _spawnLike(options) {
839
+ return this._createLike([], options);
840
+ }
868
841
  }
869
842
  exports.SinglyLinkedList = SinglyLinkedList;
843
+ function elementOrPredicate(input, equals) {
844
+ if (input instanceof SinglyLinkedListNode)
845
+ return (node) => node === input;
846
+ if (typeof input === 'function')
847
+ return input;
848
+ const value = input;
849
+ return (node) => equals(node.value, value);
850
+ }