linked-list-typed 1.53.5 → 1.53.7
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/README.md +432 -10
- package/dist/common/index.d.ts +12 -0
- package/dist/common/index.js +23 -0
- package/dist/data-structures/binary-tree/avl-tree-multi-map.js +7 -10
- package/dist/data-structures/binary-tree/avl-tree.js +2 -2
- package/dist/data-structures/binary-tree/binary-tree.d.ts +54 -19
- package/dist/data-structures/binary-tree/binary-tree.js +100 -66
- package/dist/data-structures/binary-tree/bst.d.ts +100 -36
- package/dist/data-structures/binary-tree/bst.js +185 -66
- package/dist/data-structures/binary-tree/rb-tree.d.ts +4 -0
- package/dist/data-structures/binary-tree/rb-tree.js +6 -2
- package/dist/data-structures/binary-tree/tree-multi-map.js +2 -2
- package/dist/data-structures/heap/heap.d.ts +6 -6
- package/dist/data-structures/heap/heap.js +6 -6
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +31 -19
- package/dist/data-structures/linked-list/doubly-linked-list.js +49 -34
- package/dist/data-structures/linked-list/singly-linked-list.d.ts +144 -62
- package/dist/data-structures/linked-list/singly-linked-list.js +201 -97
- package/dist/data-structures/trie/trie.d.ts +104 -4
- package/dist/data-structures/trie/trie.js +116 -12
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/bst.d.ts +3 -2
- package/dist/types/data-structures/binary-tree/rb-tree.d.ts +1 -1
- package/dist/types/utils/utils.d.ts +10 -6
- package/dist/utils/utils.js +4 -2
- package/package.json +2 -2
- package/src/common/index.ts +19 -0
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +7 -9
- package/src/data-structures/binary-tree/avl-tree.ts +3 -2
- package/src/data-structures/binary-tree/binary-tree.ts +108 -64
- package/src/data-structures/binary-tree/bst.ts +190 -69
- package/src/data-structures/binary-tree/rb-tree.ts +6 -2
- package/src/data-structures/binary-tree/tree-multi-map.ts +3 -3
- package/src/data-structures/heap/heap.ts +39 -39
- package/src/data-structures/linked-list/doubly-linked-list.ts +139 -121
- package/src/data-structures/linked-list/singly-linked-list.ts +219 -98
- package/src/data-structures/trie/trie.ts +116 -11
- package/src/index.ts +2 -2
- package/src/types/data-structures/binary-tree/binary-tree.ts +1 -1
- package/src/types/data-structures/binary-tree/bst.ts +3 -2
- package/src/types/data-structures/binary-tree/rb-tree.ts +1 -1
- package/src/types/utils/utils.ts +16 -10
- package/src/utils/utils.ts +4 -2
|
@@ -82,52 +82,52 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
85
|
+
*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.
|
|
86
86
|
* 2. Bidirectional Traversal: Unlike singly linked lists, doubly linked lists can be easily traversed forwards or backwards. This makes insertions and deletions in the list more flexible and efficient.
|
|
87
87
|
* 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.
|
|
88
88
|
* 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.
|
|
89
|
-
* @example
|
|
90
|
-
* // text editor operation history
|
|
91
|
-
*
|
|
89
|
+
* @example
|
|
90
|
+
* // text editor operation history
|
|
91
|
+
* const actions = [
|
|
92
92
|
* { type: 'insert', content: 'first line of text' },
|
|
93
93
|
* { type: 'insert', content: 'second line of text' },
|
|
94
94
|
* { type: 'delete', content: 'delete the first line' }
|
|
95
95
|
* ];
|
|
96
96
|
* const editorHistory = new DoublyLinkedList<{ type: string; content: string }>(actions);
|
|
97
|
-
*
|
|
97
|
+
*
|
|
98
98
|
* console.log(editorHistory.last?.type); // 'delete'
|
|
99
99
|
* console.log(editorHistory.pop()?.content); // 'delete the first line'
|
|
100
100
|
* console.log(editorHistory.last?.type); // 'insert'
|
|
101
|
-
* @example
|
|
102
|
-
* // Browser history
|
|
103
|
-
*
|
|
104
|
-
*
|
|
101
|
+
* @example
|
|
102
|
+
* // Browser history
|
|
103
|
+
* const browserHistory = new DoublyLinkedList<string>();
|
|
104
|
+
*
|
|
105
105
|
* browserHistory.push('home page');
|
|
106
106
|
* browserHistory.push('search page');
|
|
107
107
|
* browserHistory.push('details page');
|
|
108
|
-
*
|
|
108
|
+
*
|
|
109
109
|
* console.log(browserHistory.last); // 'details page'
|
|
110
110
|
* console.log(browserHistory.pop()); // 'details page'
|
|
111
111
|
* console.log(browserHistory.last); // 'search page'
|
|
112
|
-
* @example
|
|
113
|
-
* // Use DoublyLinkedList to implement music player
|
|
114
|
-
*
|
|
112
|
+
* @example
|
|
113
|
+
* // Use DoublyLinkedList to implement music player
|
|
114
|
+
* // Define the Song interface
|
|
115
115
|
* interface Song {
|
|
116
116
|
* title: string;
|
|
117
117
|
* artist: string;
|
|
118
118
|
* duration: number; // duration in seconds
|
|
119
119
|
* }
|
|
120
|
-
*
|
|
120
|
+
*
|
|
121
121
|
* class Player {
|
|
122
122
|
* private playlist: DoublyLinkedList<Song>;
|
|
123
123
|
* private currentSong: ReturnType<typeof this.playlist.getNodeAt> | undefined;
|
|
124
|
-
*
|
|
124
|
+
*
|
|
125
125
|
* constructor(songs: Song[]) {
|
|
126
126
|
* this.playlist = new DoublyLinkedList<Song>();
|
|
127
127
|
* songs.forEach(song => this.playlist.push(song));
|
|
128
128
|
* this.currentSong = this.playlist.head;
|
|
129
129
|
* }
|
|
130
|
-
*
|
|
130
|
+
*
|
|
131
131
|
* // Play the next song in the playlist
|
|
132
132
|
* playNext(): Song | undefined {
|
|
133
133
|
* if (!this.currentSong?.next) {
|
|
@@ -137,7 +137,7 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
137
137
|
* }
|
|
138
138
|
* return this.currentSong?.value;
|
|
139
139
|
* }
|
|
140
|
-
*
|
|
140
|
+
*
|
|
141
141
|
* // Play the previous song in the playlist
|
|
142
142
|
* playPrevious(): Song | undefined {
|
|
143
143
|
* if (!this.currentSong?.prev) {
|
|
@@ -147,29 +147,29 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
147
147
|
* }
|
|
148
148
|
* return this.currentSong?.value;
|
|
149
149
|
* }
|
|
150
|
-
*
|
|
150
|
+
*
|
|
151
151
|
* // Get the current song
|
|
152
152
|
* getCurrentSong(): Song | undefined {
|
|
153
153
|
* return this.currentSong?.value;
|
|
154
154
|
* }
|
|
155
|
-
*
|
|
155
|
+
*
|
|
156
156
|
* // Loop through the playlist twice
|
|
157
157
|
* loopThroughPlaylist(): Song[] {
|
|
158
158
|
* const playedSongs: Song[] = [];
|
|
159
159
|
* const initialNode = this.currentSong;
|
|
160
|
-
*
|
|
160
|
+
*
|
|
161
161
|
* // Loop through the playlist twice
|
|
162
162
|
* for (let i = 0; i < this.playlist.size * 2; i++) {
|
|
163
163
|
* playedSongs.push(this.currentSong!.value);
|
|
164
164
|
* this.currentSong = this.currentSong!.next || this.playlist.head; // Loop back to the start if needed
|
|
165
165
|
* }
|
|
166
|
-
*
|
|
166
|
+
*
|
|
167
167
|
* // Reset the current song to the initial song
|
|
168
168
|
* this.currentSong = initialNode;
|
|
169
169
|
* return playedSongs;
|
|
170
170
|
* }
|
|
171
171
|
* }
|
|
172
|
-
*
|
|
172
|
+
*
|
|
173
173
|
* const songs = [
|
|
174
174
|
* { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 354 },
|
|
175
175
|
* { title: 'Hotel California', artist: 'Eagles', duration: 391 },
|
|
@@ -181,48 +181,48 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
181
181
|
* player = new Player(songs);
|
|
182
182
|
* const firstSong = player.getCurrentSong();
|
|
183
183
|
* const nextSong = player.playNext();
|
|
184
|
-
*
|
|
184
|
+
*
|
|
185
185
|
* // Expect the next song to be "Hotel California by Eagles"
|
|
186
186
|
* console.log(nextSong); // { title: 'Hotel California', artist: 'Eagles', duration: 391 }
|
|
187
187
|
* console.log(firstSong); // { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 354 }
|
|
188
|
-
*
|
|
188
|
+
*
|
|
189
189
|
* // should play the previous song
|
|
190
190
|
* player = new Player(songs);
|
|
191
191
|
* player.playNext(); // Move to the second song
|
|
192
192
|
* const currentSong = player.getCurrentSong();
|
|
193
193
|
* const previousSong = player.playPrevious();
|
|
194
|
-
*
|
|
194
|
+
*
|
|
195
195
|
* // Expect the previous song to be "Bohemian Rhapsody by Queen"
|
|
196
196
|
* console.log(previousSong); // { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 354 }
|
|
197
197
|
* console.log(currentSong); // { title: 'Hotel California', artist: 'Eagles', duration: 391 }
|
|
198
|
-
*
|
|
198
|
+
*
|
|
199
199
|
* // should loop to the first song when playing next from the last song
|
|
200
200
|
* player = new Player(songs);
|
|
201
201
|
* player.playNext(); // Move to the second song
|
|
202
202
|
* player.playNext(); // Move to the third song
|
|
203
203
|
* player.playNext(); // Move to the fourth song
|
|
204
|
-
*
|
|
204
|
+
*
|
|
205
205
|
* const nextSongToFirst = player.playNext(); // Should loop to the first song
|
|
206
|
-
*
|
|
206
|
+
*
|
|
207
207
|
* // Expect the next song to be "Bohemian Rhapsody by Queen"
|
|
208
208
|
* console.log(nextSongToFirst); // { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 354 }
|
|
209
|
-
*
|
|
209
|
+
*
|
|
210
210
|
* // should loop to the last song when playing previous from the first song
|
|
211
211
|
* player = new Player(songs);
|
|
212
212
|
* player.playNext(); // Move to the first song
|
|
213
213
|
* player.playNext(); // Move to the second song
|
|
214
214
|
* player.playNext(); // Move to the third song
|
|
215
215
|
* player.playNext(); // Move to the fourth song
|
|
216
|
-
*
|
|
216
|
+
*
|
|
217
217
|
* const previousToLast = player.playPrevious(); // Should loop to the last song
|
|
218
|
-
*
|
|
218
|
+
*
|
|
219
219
|
* // Expect the previous song to be "Billie Jean by Michael Jackson"
|
|
220
220
|
* console.log(previousToLast); // { title: 'Billie Jean', artist: 'Michael Jackson', duration: 294 }
|
|
221
|
-
*
|
|
221
|
+
*
|
|
222
222
|
* // should loop through the entire playlist
|
|
223
223
|
* player = new Player(songs);
|
|
224
224
|
* const playedSongs = player.loopThroughPlaylist();
|
|
225
|
-
*
|
|
225
|
+
*
|
|
226
226
|
* // The expected order of songs for two loops
|
|
227
227
|
* console.log(playedSongs); // [
|
|
228
228
|
* // { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 354 },
|
|
@@ -234,18 +234,18 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
234
234
|
* // { title: 'Shape of You', artist: 'Ed Sheeran', duration: 233 },
|
|
235
235
|
* // { title: 'Billie Jean', artist: 'Michael Jackson', duration: 294 }
|
|
236
236
|
* // ]
|
|
237
|
-
* @example
|
|
238
|
-
* // Use DoublyLinkedList to implement LRU cache
|
|
239
|
-
*
|
|
237
|
+
* @example
|
|
238
|
+
* // Use DoublyLinkedList to implement LRU cache
|
|
239
|
+
* interface CacheEntry<K, V> {
|
|
240
240
|
* key: K;
|
|
241
241
|
* value: V;
|
|
242
242
|
* }
|
|
243
|
-
*
|
|
243
|
+
*
|
|
244
244
|
* class LRUCache<K = string, V = any> {
|
|
245
245
|
* private readonly capacity: number;
|
|
246
246
|
* private list: DoublyLinkedList<CacheEntry<K, V>>;
|
|
247
247
|
* private map: Map<K, DoublyLinkedListNode<CacheEntry<K, V>>>;
|
|
248
|
-
*
|
|
248
|
+
*
|
|
249
249
|
* constructor(capacity: number) {
|
|
250
250
|
* if (capacity <= 0) {
|
|
251
251
|
* throw new Error('lru cache capacity must be greater than 0');
|
|
@@ -254,31 +254,31 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
254
254
|
* this.list = new DoublyLinkedList<CacheEntry<K, V>>();
|
|
255
255
|
* this.map = new Map<K, DoublyLinkedListNode<CacheEntry<K, V>>>();
|
|
256
256
|
* }
|
|
257
|
-
*
|
|
257
|
+
*
|
|
258
258
|
* // Get cached value
|
|
259
259
|
* get(key: K): V | undefined {
|
|
260
260
|
* const node = this.map.get(key);
|
|
261
|
-
*
|
|
261
|
+
*
|
|
262
262
|
* if (!node) return undefined;
|
|
263
|
-
*
|
|
263
|
+
*
|
|
264
264
|
* // Move the visited node to the head of the linked list (most recently used)
|
|
265
265
|
* this.moveToFront(node);
|
|
266
|
-
*
|
|
266
|
+
*
|
|
267
267
|
* return node.value.value;
|
|
268
268
|
* }
|
|
269
|
-
*
|
|
269
|
+
*
|
|
270
270
|
* // Set cache value
|
|
271
271
|
* set(key: K, value: V): void {
|
|
272
272
|
* // Check if it already exists
|
|
273
273
|
* const node = this.map.get(key);
|
|
274
|
-
*
|
|
274
|
+
*
|
|
275
275
|
* if (node) {
|
|
276
276
|
* // Update value and move to head
|
|
277
277
|
* node.value.value = value;
|
|
278
278
|
* this.moveToFront(node);
|
|
279
279
|
* return;
|
|
280
280
|
* }
|
|
281
|
-
*
|
|
281
|
+
*
|
|
282
282
|
* // Check capacity
|
|
283
283
|
* if (this.list.size >= this.capacity) {
|
|
284
284
|
* // Delete the least recently used element (the tail of the linked list)
|
|
@@ -288,119 +288,119 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
288
288
|
* this.list.pop();
|
|
289
289
|
* }
|
|
290
290
|
* }
|
|
291
|
-
*
|
|
291
|
+
*
|
|
292
292
|
* // Create new node and add to head
|
|
293
293
|
* const newEntry: CacheEntry<K, V> = { key, value };
|
|
294
294
|
* this.list.unshift(newEntry);
|
|
295
|
-
*
|
|
295
|
+
*
|
|
296
296
|
* // Save node reference in map
|
|
297
297
|
* const newNode = this.list.head;
|
|
298
298
|
* if (newNode) {
|
|
299
299
|
* this.map.set(key, newNode);
|
|
300
300
|
* }
|
|
301
301
|
* }
|
|
302
|
-
*
|
|
302
|
+
*
|
|
303
303
|
* // Move the node to the head of the linked list
|
|
304
304
|
* private moveToFront(node: DoublyLinkedListNode<CacheEntry<K, V>>): void {
|
|
305
305
|
* this.list.delete(node);
|
|
306
306
|
* this.list.unshift(node.value);
|
|
307
307
|
* }
|
|
308
|
-
*
|
|
308
|
+
*
|
|
309
309
|
* // Delete specific key
|
|
310
310
|
* delete(key: K): boolean {
|
|
311
311
|
* const node = this.map.get(key);
|
|
312
312
|
* if (!node) return false;
|
|
313
|
-
*
|
|
313
|
+
*
|
|
314
314
|
* // Remove from linked list
|
|
315
315
|
* this.list.delete(node);
|
|
316
316
|
* // Remove from map
|
|
317
317
|
* this.map.delete(key);
|
|
318
|
-
*
|
|
318
|
+
*
|
|
319
319
|
* return true;
|
|
320
320
|
* }
|
|
321
|
-
*
|
|
321
|
+
*
|
|
322
322
|
* // Clear cache
|
|
323
323
|
* clear(): void {
|
|
324
324
|
* this.list.clear();
|
|
325
325
|
* this.map.clear();
|
|
326
326
|
* }
|
|
327
|
-
*
|
|
327
|
+
*
|
|
328
328
|
* // Get the current cache size
|
|
329
329
|
* get size(): number {
|
|
330
330
|
* return this.list.size;
|
|
331
331
|
* }
|
|
332
|
-
*
|
|
332
|
+
*
|
|
333
333
|
* // Check if it is empty
|
|
334
334
|
* get isEmpty(): boolean {
|
|
335
335
|
* return this.list.isEmpty();
|
|
336
336
|
* }
|
|
337
337
|
* }
|
|
338
|
-
*
|
|
338
|
+
*
|
|
339
339
|
* // should set and get values correctly
|
|
340
340
|
* const cache = new LRUCache<string, number>(3);
|
|
341
341
|
* cache.set('a', 1);
|
|
342
342
|
* cache.set('b', 2);
|
|
343
343
|
* cache.set('c', 3);
|
|
344
|
-
*
|
|
344
|
+
*
|
|
345
345
|
* console.log(cache.get('a')); // 1
|
|
346
346
|
* console.log(cache.get('b')); // 2
|
|
347
347
|
* console.log(cache.get('c')); // 3
|
|
348
|
-
*
|
|
348
|
+
*
|
|
349
349
|
* // The least recently used element should be evicted when capacity is exceeded
|
|
350
350
|
* cache.clear();
|
|
351
351
|
* cache.set('a', 1);
|
|
352
352
|
* cache.set('b', 2);
|
|
353
353
|
* cache.set('c', 3);
|
|
354
354
|
* cache.set('d', 4); // This will eliminate 'a'
|
|
355
|
-
*
|
|
355
|
+
*
|
|
356
356
|
* console.log(cache.get('a')); // undefined
|
|
357
357
|
* console.log(cache.get('b')); // 2
|
|
358
358
|
* console.log(cache.get('c')); // 3
|
|
359
359
|
* console.log(cache.get('d')); // 4
|
|
360
|
-
*
|
|
360
|
+
*
|
|
361
361
|
* // The priority of an element should be updated when it is accessed
|
|
362
362
|
* cache.clear();
|
|
363
363
|
* cache.set('a', 1);
|
|
364
364
|
* cache.set('b', 2);
|
|
365
365
|
* cache.set('c', 3);
|
|
366
|
-
*
|
|
366
|
+
*
|
|
367
367
|
* cache.get('a'); // access 'a'
|
|
368
368
|
* cache.set('d', 4); // This will eliminate 'b'
|
|
369
|
-
*
|
|
369
|
+
*
|
|
370
370
|
* console.log(cache.get('a')); // 1
|
|
371
371
|
* console.log(cache.get('b')); // undefined
|
|
372
372
|
* console.log(cache.get('c')); // 3
|
|
373
373
|
* console.log(cache.get('d')); // 4
|
|
374
|
-
*
|
|
374
|
+
*
|
|
375
375
|
* // Should support updating existing keys
|
|
376
376
|
* cache.clear();
|
|
377
377
|
* cache.set('a', 1);
|
|
378
378
|
* cache.set('a', 10);
|
|
379
|
-
*
|
|
379
|
+
*
|
|
380
380
|
* console.log(cache.get('a')); // 10
|
|
381
|
-
*
|
|
381
|
+
*
|
|
382
382
|
* // Should support deleting specified keys
|
|
383
383
|
* cache.clear();
|
|
384
384
|
* cache.set('a', 1);
|
|
385
385
|
* cache.set('b', 2);
|
|
386
|
-
*
|
|
386
|
+
*
|
|
387
387
|
* console.log(cache.delete('a')); // true
|
|
388
388
|
* console.log(cache.get('a')); // undefined
|
|
389
389
|
* console.log(cache.size); // 1
|
|
390
|
-
*
|
|
390
|
+
*
|
|
391
391
|
* // Should support clearing cache
|
|
392
392
|
* cache.clear();
|
|
393
393
|
* cache.set('a', 1);
|
|
394
394
|
* cache.set('b', 2);
|
|
395
395
|
* cache.clear();
|
|
396
|
-
*
|
|
396
|
+
*
|
|
397
397
|
* console.log(cache.size); // 0
|
|
398
398
|
* console.log(cache.isEmpty); // true
|
|
399
|
-
* @example
|
|
400
|
-
* // finding lyrics by timestamp in Coldplay's "Fix You"
|
|
401
|
-
*
|
|
399
|
+
* @example
|
|
400
|
+
* // finding lyrics by timestamp in Coldplay's "Fix You"
|
|
401
|
+
* // Create a DoublyLinkedList to store song lyrics with timestamps
|
|
402
402
|
* const lyricsList = new DoublyLinkedList<{ time: number; text: string }>();
|
|
403
|
-
*
|
|
403
|
+
*
|
|
404
404
|
* // Detailed lyrics with precise timestamps (in milliseconds)
|
|
405
405
|
* const lyrics = [
|
|
406
406
|
* { time: 0, text: "When you try your best, but you don't succeed" },
|
|
@@ -415,105 +415,115 @@ export class DoublyLinkedListNode<E = any> {
|
|
|
415
415
|
* { time: 36000, text: 'And ignite your bones' },
|
|
416
416
|
* { time: 40000, text: 'And I will try to fix you' }
|
|
417
417
|
* ];
|
|
418
|
-
*
|
|
418
|
+
*
|
|
419
419
|
* // Populate the DoublyLinkedList with lyrics
|
|
420
420
|
* lyrics.forEach(lyric => lyricsList.push(lyric));
|
|
421
|
-
*
|
|
421
|
+
*
|
|
422
422
|
* // Test different scenarios of lyric synchronization
|
|
423
|
-
*
|
|
423
|
+
*
|
|
424
424
|
* // 1. Find lyric at exact timestamp
|
|
425
425
|
* const exactTimeLyric = lyricsList.getBackward(lyric => lyric.value.time <= 36000);
|
|
426
426
|
* console.log(exactTimeLyric?.text); // 'And ignite your bones'
|
|
427
|
-
*
|
|
427
|
+
*
|
|
428
428
|
* // 2. Find lyric between timestamps
|
|
429
429
|
* const betweenTimeLyric = lyricsList.getBackward(lyric => lyric.value.time <= 22000);
|
|
430
430
|
* console.log(betweenTimeLyric?.text); // "When you lose something you can't replace"
|
|
431
|
-
*
|
|
431
|
+
*
|
|
432
432
|
* // 3. Find first lyric when timestamp is less than first entry
|
|
433
433
|
* const earlyTimeLyric = lyricsList.getBackward(lyric => lyric.value.time <= -1000);
|
|
434
434
|
* console.log(earlyTimeLyric); // undefined
|
|
435
|
-
*
|
|
435
|
+
*
|
|
436
436
|
* // 4. Find last lyric when timestamp is after last entry
|
|
437
437
|
* const lateTimeLyric = lyricsList.getBackward(lyric => lyric.value.time <= 50000);
|
|
438
438
|
* console.log(lateTimeLyric?.text); // 'And I will try to fix you'
|
|
439
|
-
* @example
|
|
440
|
-
* // cpu process schedules
|
|
441
|
-
*
|
|
439
|
+
* @example
|
|
440
|
+
* // cpu process schedules
|
|
441
|
+
* class Process {
|
|
442
442
|
* constructor(
|
|
443
443
|
* public id: number,
|
|
444
444
|
* public priority: number
|
|
445
445
|
* ) {}
|
|
446
|
-
*
|
|
446
|
+
*
|
|
447
447
|
* execute(): string {
|
|
448
448
|
* return `Process ${this.id} executed.`;
|
|
449
449
|
* }
|
|
450
450
|
* }
|
|
451
|
-
*
|
|
451
|
+
*
|
|
452
452
|
* class Scheduler {
|
|
453
453
|
* private queue: DoublyLinkedList<Process>;
|
|
454
|
-
*
|
|
454
|
+
*
|
|
455
455
|
* constructor() {
|
|
456
456
|
* this.queue = new DoublyLinkedList<Process>();
|
|
457
457
|
* }
|
|
458
|
-
*
|
|
458
|
+
*
|
|
459
459
|
* addProcess(process: Process): void {
|
|
460
460
|
* // Insert processes into a queue based on priority, keeping priority in descending order
|
|
461
461
|
* let current = this.queue.head;
|
|
462
462
|
* while (current && current.value.priority >= process.priority) {
|
|
463
463
|
* current = current.next;
|
|
464
464
|
* }
|
|
465
|
-
*
|
|
465
|
+
*
|
|
466
466
|
* if (!current) {
|
|
467
467
|
* this.queue.push(process);
|
|
468
468
|
* } else {
|
|
469
469
|
* this.queue.addBefore(current, process);
|
|
470
470
|
* }
|
|
471
471
|
* }
|
|
472
|
-
*
|
|
472
|
+
*
|
|
473
473
|
* executeNext(): string | undefined {
|
|
474
474
|
* // Execute tasks at the head of the queue in order
|
|
475
475
|
* const process = this.queue.shift();
|
|
476
476
|
* return process ? process.execute() : undefined;
|
|
477
477
|
* }
|
|
478
|
-
*
|
|
478
|
+
*
|
|
479
479
|
* listProcesses(): string[] {
|
|
480
480
|
* return this.queue.toArray().map(process => `Process ${process.id} (Priority: ${process.priority})`);
|
|
481
481
|
* }
|
|
482
|
-
*
|
|
482
|
+
*
|
|
483
483
|
* clear(): void {
|
|
484
484
|
* this.queue.clear();
|
|
485
485
|
* }
|
|
486
486
|
* }
|
|
487
|
-
*
|
|
487
|
+
*
|
|
488
488
|
* // should add processes based on priority
|
|
489
489
|
* let scheduler = new Scheduler();
|
|
490
490
|
* scheduler.addProcess(new Process(1, 10));
|
|
491
491
|
* scheduler.addProcess(new Process(2, 20));
|
|
492
492
|
* scheduler.addProcess(new Process(3, 15));
|
|
493
|
-
*
|
|
493
|
+
*
|
|
494
494
|
* console.log(scheduler.listProcesses()); // [
|
|
495
495
|
* // 'Process 2 (Priority: 20)',
|
|
496
496
|
* // 'Process 3 (Priority: 15)',
|
|
497
497
|
* // 'Process 1 (Priority: 10)'
|
|
498
498
|
* // ]
|
|
499
|
-
*
|
|
499
|
+
*
|
|
500
500
|
* // should execute the highest priority process
|
|
501
501
|
* scheduler = new Scheduler();
|
|
502
502
|
* scheduler.addProcess(new Process(1, 10));
|
|
503
503
|
* scheduler.addProcess(new Process(2, 20));
|
|
504
|
-
*
|
|
504
|
+
*
|
|
505
505
|
* console.log(scheduler.executeNext()); // 'Process 2 executed.'
|
|
506
506
|
* console.log(scheduler.listProcesses()); // ['Process 1 (Priority: 10)']
|
|
507
|
-
*
|
|
507
|
+
*
|
|
508
508
|
* // should clear all processes
|
|
509
509
|
* scheduler = new Scheduler();
|
|
510
510
|
* scheduler.addProcess(new Process(1, 10));
|
|
511
511
|
* scheduler.addProcess(new Process(2, 20));
|
|
512
|
-
*
|
|
512
|
+
*
|
|
513
513
|
* scheduler.clear();
|
|
514
514
|
* console.log(scheduler.listProcesses()); // []
|
|
515
515
|
*/
|
|
516
516
|
export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R, DoublyLinkedList<E, R>> {
|
|
517
|
+
/**
|
|
518
|
+
* This TypeScript constructor initializes a DoublyLinkedList with optional elements and options.
|
|
519
|
+
* @param {Iterable<E> | Iterable<R>} elements - The `elements` parameter in the constructor is an
|
|
520
|
+
* iterable collection of elements of type `E` or `R`. It is used to initialize the DoublyLinkedList
|
|
521
|
+
* with the elements provided in the iterable. If no elements are provided, the default value is an
|
|
522
|
+
* empty iterable.
|
|
523
|
+
* @param [options] - The `options` parameter in the constructor is of type
|
|
524
|
+
* `DoublyLinkedListOptions<E, R>`. It is an optional parameter that allows you to pass additional
|
|
525
|
+
* configuration options to customize the behavior of the DoublyLinkedList.
|
|
526
|
+
*/
|
|
517
527
|
constructor(elements: Iterable<E> | Iterable<R> = [], options?: DoublyLinkedListOptions<E, R>) {
|
|
518
528
|
super(options);
|
|
519
529
|
this._head = undefined;
|
|
@@ -819,13 +829,9 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
819
829
|
existingElementOrNode: E | DoublyLinkedListNode<E>,
|
|
820
830
|
newElementOrNode: E | DoublyLinkedListNode<E>
|
|
821
831
|
): boolean {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
existingNode = existingElementOrNode;
|
|
826
|
-
} else {
|
|
827
|
-
existingNode = this.getNode(existingElementOrNode);
|
|
828
|
-
}
|
|
832
|
+
const existingNode: DoublyLinkedListNode<E> | undefined = this.isNode(existingElementOrNode)
|
|
833
|
+
? existingElementOrNode
|
|
834
|
+
: this.getNode(existingElementOrNode);
|
|
829
835
|
|
|
830
836
|
if (existingNode) {
|
|
831
837
|
const newNode = this._ensureNode(newElementOrNode);
|
|
@@ -862,13 +868,9 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
862
868
|
* was not found in the linked list.
|
|
863
869
|
*/
|
|
864
870
|
addAfter(existingElementOrNode: E | DoublyLinkedListNode<E>, newElementOrNode: E | DoublyLinkedListNode<E>): boolean {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
existingNode = existingElementOrNode;
|
|
869
|
-
} else {
|
|
870
|
-
existingNode = this.getNode(existingElementOrNode);
|
|
871
|
-
}
|
|
871
|
+
const existingNode: DoublyLinkedListNode<E> | undefined = this.isNode(existingElementOrNode)
|
|
872
|
+
? existingElementOrNode
|
|
873
|
+
: this.getNode(existingElementOrNode);
|
|
872
874
|
|
|
873
875
|
if (existingNode) {
|
|
874
876
|
const newNode = this._ensureNode(newElementOrNode);
|
|
@@ -978,17 +980,15 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
978
980
|
* Time Complexity: O(n)
|
|
979
981
|
* Space Complexity: O(1)
|
|
980
982
|
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
985
|
-
*
|
|
986
|
-
*
|
|
987
|
-
* list. If the element or node is found in the list, the method returns the index of that element or
|
|
988
|
-
* node. If the element or node is not found in the list, the method returns -1.
|
|
983
|
+
* This function finds the index of a specified element, node, or predicate in a doubly linked list.
|
|
984
|
+
* @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
|
|
985
|
+
* elementNodeOrPredicate - The `indexOf` method takes in a parameter `elementNodeOrPredicate`, which
|
|
986
|
+
* can be one of the following:
|
|
987
|
+
* @returns The `indexOf` method returns the index of the element in the doubly linked list that
|
|
988
|
+
* matches the provided element, node, or predicate. If no match is found, it returns -1.
|
|
989
989
|
*/
|
|
990
|
-
indexOf(
|
|
991
|
-
const predicate = this._ensurePredicate(
|
|
990
|
+
indexOf(elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)): number {
|
|
991
|
+
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
992
992
|
let index = 0;
|
|
993
993
|
let current = this.head;
|
|
994
994
|
while (current) {
|
|
@@ -1005,8 +1005,6 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
1005
1005
|
* Time Complexity: O(n)
|
|
1006
1006
|
* Space Complexity: O(1)
|
|
1007
1007
|
*
|
|
1008
|
-
*/
|
|
1009
|
-
/**
|
|
1010
1008
|
* This function retrieves an element from a doubly linked list based on a given element
|
|
1011
1009
|
* node or predicate.
|
|
1012
1010
|
* @param {E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
|
|
@@ -1015,7 +1013,7 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
1015
1013
|
* @returns The `get` method returns the value of the first node in the doubly linked list that
|
|
1016
1014
|
* satisfies the provided predicate function. If no such node is found, it returns `undefined`.
|
|
1017
1015
|
*/
|
|
1018
|
-
|
|
1016
|
+
search(
|
|
1019
1017
|
elementNodeOrPredicate: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)
|
|
1020
1018
|
): E | undefined {
|
|
1021
1019
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
@@ -1180,6 +1178,26 @@ export class DoublyLinkedList<E = any, R = any> extends IterableElementBase<E, R
|
|
|
1180
1178
|
return mappedList;
|
|
1181
1179
|
}
|
|
1182
1180
|
|
|
1181
|
+
/**
|
|
1182
|
+
* Time Complexity: O(n)
|
|
1183
|
+
* Space Complexity: O(1)
|
|
1184
|
+
*
|
|
1185
|
+
*/
|
|
1186
|
+
countOccurrences(elementOrNode: E | DoublyLinkedListNode<E> | ((node: DoublyLinkedListNode<E>) => boolean)): number {
|
|
1187
|
+
const predicate = this._ensurePredicate(elementOrNode);
|
|
1188
|
+
let count = 0;
|
|
1189
|
+
let current = this.head;
|
|
1190
|
+
|
|
1191
|
+
while (current) {
|
|
1192
|
+
if (predicate(current)) {
|
|
1193
|
+
count++;
|
|
1194
|
+
}
|
|
1195
|
+
current = current.next;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
return count;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1183
1201
|
/**
|
|
1184
1202
|
* Time Complexity: O(n)
|
|
1185
1203
|
* Space Complexity: O(n)
|