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