binary-tree-typed 2.4.4 → 2.5.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/README.md +0 -84
- package/dist/cjs/index.cjs +965 -420
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +962 -417
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +965 -421
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +962 -418
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/types/common/error.d.ts +23 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +128 -51
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +210 -164
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +439 -78
- package/dist/types/data-structures/binary-tree/bst.d.ts +311 -28
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +217 -31
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +218 -152
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +1281 -5
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1087 -201
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +858 -65
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +1133 -5
- package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +220 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +218 -59
- package/dist/types/data-structures/hash/hash-map.d.ts +230 -77
- package/dist/types/data-structures/heap/heap.d.ts +287 -99
- package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
- package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +286 -44
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +278 -65
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +415 -12
- package/dist/types/data-structures/matrix/matrix.d.ts +331 -0
- package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
- package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
- package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
- package/dist/types/data-structures/queue/deque.d.ts +313 -66
- package/dist/types/data-structures/queue/queue.d.ts +211 -42
- package/dist/types/data-structures/stack/stack.d.ts +174 -32
- package/dist/types/data-structures/trie/trie.d.ts +213 -43
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
- package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
- package/dist/umd/binary-tree-typed.js +959 -414
- package/dist/umd/binary-tree-typed.js.map +1 -1
- package/dist/umd/binary-tree-typed.min.js +3 -3
- package/dist/umd/binary-tree-typed.min.js.map +1 -1
- package/package.json +2 -2
- package/src/common/error.ts +60 -0
- package/src/common/index.ts +2 -0
- package/src/data-structures/base/iterable-element-base.ts +2 -2
- package/src/data-structures/binary-tree/avl-tree.ts +134 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +303 -247
- package/src/data-structures/binary-tree/binary-tree.ts +542 -121
- package/src/data-structures/binary-tree/bst.ts +346 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +309 -96
- package/src/data-structures/binary-tree/segment-tree.ts +372 -248
- package/src/data-structures/binary-tree/tree-map.ts +1292 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1098 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +863 -69
- package/src/data-structures/binary-tree/tree-set.ts +1143 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +223 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +299 -59
- package/src/data-structures/hash/hash-map.ts +243 -79
- package/src/data-structures/heap/heap.ts +291 -102
- package/src/data-structures/heap/max-heap.ts +48 -3
- package/src/data-structures/heap/min-heap.ts +59 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +286 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +278 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +689 -90
- package/src/data-structures/matrix/matrix.ts +425 -22
- package/src/data-structures/priority-queue/max-priority-queue.ts +59 -3
- package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
- package/src/data-structures/priority-queue/priority-queue.ts +60 -0
- package/src/data-structures/queue/deque.ts +343 -68
- package/src/data-structures/queue/queue.ts +211 -42
- package/src/data-structures/stack/stack.ts +174 -32
- package/src/data-structures/trie/trie.ts +215 -44
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
- package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
- package/src/types/data-structures/queue/deque.ts +7 -0
- package/src/utils/utils.ts +4 -2
|
@@ -11,6 +11,66 @@ import { Heap } from '../heap';
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @example
|
|
14
|
+
* // Hospital emergency room triage
|
|
15
|
+
* interface Patient {
|
|
16
|
+
* name: string;
|
|
17
|
+
* severity: number; // 1 = critical, 5 = minor
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* const er = new PriorityQueue<Patient>([], {
|
|
21
|
+
* comparator: (a, b) => a.severity - b.severity
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* er.add({ name: 'Flu symptoms', severity: 4 });
|
|
25
|
+
* er.add({ name: 'Heart attack', severity: 1 });
|
|
26
|
+
* er.add({ name: 'Broken arm', severity: 3 });
|
|
27
|
+
* er.add({ name: 'Stroke', severity: 1 });
|
|
28
|
+
*
|
|
29
|
+
* // Most critical patients first
|
|
30
|
+
* console.log(er.poll()?.severity); // 1;
|
|
31
|
+
* console.log(er.poll()?.severity); // 1;
|
|
32
|
+
* console.log(er.poll()?.severity); // 3;
|
|
33
|
+
* console.log(er.poll()?.severity); // 4;
|
|
34
|
+
* @example
|
|
35
|
+
* // Task scheduler with deadlines
|
|
36
|
+
* interface Task {
|
|
37
|
+
* name: string;
|
|
38
|
+
* deadline: number; // hours until due
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* const scheduler = new PriorityQueue<Task>([], {
|
|
42
|
+
* comparator: (a, b) => a.deadline - b.deadline
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* scheduler.add({ name: 'Report', deadline: 24 });
|
|
46
|
+
* scheduler.add({ name: 'Email', deadline: 2 });
|
|
47
|
+
* scheduler.add({ name: 'Meeting prep', deadline: 4 });
|
|
48
|
+
* scheduler.add({ name: 'Code review', deadline: 8 });
|
|
49
|
+
*
|
|
50
|
+
* // Process most urgent first
|
|
51
|
+
* console.log(scheduler.peek()?.name); // 'Email';
|
|
52
|
+
* console.log(scheduler.size); // 4;
|
|
53
|
+
*
|
|
54
|
+
* const order = [];
|
|
55
|
+
* while (scheduler.size > 0) {
|
|
56
|
+
* order.push(scheduler.poll()!.name);
|
|
57
|
+
* }
|
|
58
|
+
* console.log(order); // ['Email', 'Meeting prep', 'Code review', 'Report'];
|
|
59
|
+
* @example
|
|
60
|
+
* // Bandwidth allocation with priorities
|
|
61
|
+
* const bandwidth = new PriorityQueue<[number, string]>([], {
|
|
62
|
+
* comparator: (a, b) => a[0] - b[0]
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* bandwidth.add([1, 'Video call']); // highest priority
|
|
66
|
+
* bandwidth.add([3, 'File download']);
|
|
67
|
+
* bandwidth.add([2, 'Web browsing']);
|
|
68
|
+
* bandwidth.add([1, 'Voice call']);
|
|
69
|
+
*
|
|
70
|
+
* // Allocate bandwidth to highest priority first
|
|
71
|
+
* console.log(bandwidth.poll()?.[1]); // 'Video call';
|
|
72
|
+
* console.log(bandwidth.poll()?.[1]); // 'Voice call';
|
|
73
|
+
* console.log(bandwidth.size); // 2;
|
|
14
74
|
*/
|
|
15
75
|
export class PriorityQueue<E = any, R = any> extends Heap<E, R> {
|
|
16
76
|
constructor(elements: Iterable<E> | Iterable<R> = [], options?: PriorityQueueOptions<E, R>) {
|
|
@@ -27,71 +27,6 @@ import { LinearBase } from '../base/linear-base';
|
|
|
27
27
|
* 4. Efficiency: Adding and removing elements at both ends of a deque is usually very fast. However, when the dynamic array needs to expand, it may involve copying the entire array to a larger one, and this operation has a time complexity of O(n).
|
|
28
28
|
* 5. Performance jitter: Deque may experience performance jitter, but DoublyLinkedList will not
|
|
29
29
|
* @example
|
|
30
|
-
* // basic Deque creation and push/pop operations
|
|
31
|
-
* // Create a simple Deque with initial values
|
|
32
|
-
* const deque = new Deque([1, 2, 3, 4, 5]);
|
|
33
|
-
*
|
|
34
|
-
* // Verify the deque maintains insertion order
|
|
35
|
-
* console.log([...deque]); // [1, 2, 3, 4, 5];
|
|
36
|
-
*
|
|
37
|
-
* // Check length
|
|
38
|
-
* console.log(deque.length); // 5;
|
|
39
|
-
*
|
|
40
|
-
* // Push to the end
|
|
41
|
-
* deque.push(6);
|
|
42
|
-
* console.log(deque.length); // 6;
|
|
43
|
-
*
|
|
44
|
-
* // Pop from the end
|
|
45
|
-
* const last = deque.pop();
|
|
46
|
-
* console.log(last); // 6;
|
|
47
|
-
* @example
|
|
48
|
-
* // Deque shift and unshift operations
|
|
49
|
-
* const deque = new Deque<number>([20, 30, 40]);
|
|
50
|
-
*
|
|
51
|
-
* // Unshift adds to the front
|
|
52
|
-
* deque.unshift(10);
|
|
53
|
-
* console.log([...deque]); // [10, 20, 30, 40];
|
|
54
|
-
*
|
|
55
|
-
* // Shift removes from the front (O(1) complexity!)
|
|
56
|
-
* const first = deque.shift();
|
|
57
|
-
* console.log(first); // 10;
|
|
58
|
-
*
|
|
59
|
-
* // Verify remaining elements
|
|
60
|
-
* console.log([...deque]); // [20, 30, 40];
|
|
61
|
-
* console.log(deque.length); // 3;
|
|
62
|
-
* @example
|
|
63
|
-
* // Deque peek at both ends
|
|
64
|
-
* const deque = new Deque<number>([10, 20, 30, 40, 50]);
|
|
65
|
-
*
|
|
66
|
-
* // Get first element without removing
|
|
67
|
-
* const first = deque.at(0);
|
|
68
|
-
* console.log(first); // 10;
|
|
69
|
-
*
|
|
70
|
-
* // Get last element without removing
|
|
71
|
-
* const last = deque.at(deque.length - 1);
|
|
72
|
-
* console.log(last); // 50;
|
|
73
|
-
*
|
|
74
|
-
* // Length unchanged
|
|
75
|
-
* console.log(deque.length); // 5;
|
|
76
|
-
* @example
|
|
77
|
-
* // Deque for...of iteration and reverse
|
|
78
|
-
* const deque = new Deque<string>(['A', 'B', 'C', 'D']);
|
|
79
|
-
*
|
|
80
|
-
* // Iterate forward
|
|
81
|
-
* const forward: string[] = [];
|
|
82
|
-
* for (const item of deque) {
|
|
83
|
-
* forward.push(item);
|
|
84
|
-
* }
|
|
85
|
-
* console.log(forward); // ['A', 'B', 'C', 'D'];
|
|
86
|
-
*
|
|
87
|
-
* // Reverse the deque
|
|
88
|
-
* deque.reverse();
|
|
89
|
-
* const backward: string[] = [];
|
|
90
|
-
* for (const item of deque) {
|
|
91
|
-
* backward.push(item);
|
|
92
|
-
* }
|
|
93
|
-
* console.log(backward); // ['D', 'C', 'B', 'A'];
|
|
94
|
-
* @example
|
|
95
30
|
* // Deque as sliding window for stream processing
|
|
96
31
|
* interface DataPoint {
|
|
97
32
|
* timestamp: number;
|
|
@@ -142,6 +77,10 @@ import { LinearBase } from '../base/linear-base';
|
|
|
142
77
|
* console.log(windowResults[2].windowSize); // 3; // Windows are at max size from 3rd onwards
|
|
143
78
|
* console.log(windowResults[4].windowSize); // 3; // Last window still has 3 elements
|
|
144
79
|
* console.log(dataWindow.length); // 3;
|
|
80
|
+
* @example
|
|
81
|
+
* // Convert deque to array
|
|
82
|
+
* const dq = new Deque<number>([10, 20, 30]);
|
|
83
|
+
* console.log(dq.toArray()); // [10, 20, 30];
|
|
145
84
|
*/
|
|
146
85
|
export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
147
86
|
protected _equals: (a: E, b: E) => boolean = (a, b) => Object.is(a, b);
|
|
@@ -154,12 +93,15 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
154
93
|
* @returns New Deque instance.
|
|
155
94
|
*/
|
|
156
95
|
|
|
96
|
+
constructor(elements?: IterableWithSizeOrLength<E>, options?: DequeOptions<E, R>);
|
|
97
|
+
constructor(elements: IterableWithSizeOrLength<R>, options: DequeOptions<E, R> & { toElementFn: (rawElement: R) => E });
|
|
157
98
|
constructor(elements: IterableWithSizeOrLength<E> | IterableWithSizeOrLength<R> = [], options?: DequeOptions<E, R>) {
|
|
158
99
|
super(options);
|
|
159
100
|
|
|
160
101
|
if (options) {
|
|
161
|
-
const { bucketSize } = options;
|
|
102
|
+
const { bucketSize, autoCompactRatio } = options;
|
|
162
103
|
if (typeof bucketSize === 'number') this._bucketSize = bucketSize;
|
|
104
|
+
if (typeof autoCompactRatio === 'number') this._autoCompactRatio = autoCompactRatio;
|
|
163
105
|
}
|
|
164
106
|
|
|
165
107
|
let _size: number;
|
|
@@ -191,6 +133,34 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
191
133
|
return this._bucketSize;
|
|
192
134
|
}
|
|
193
135
|
|
|
136
|
+
protected _autoCompactRatio = 0.5;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get the auto-compaction ratio.
|
|
140
|
+
* When `elements / (bucketCount * bucketSize)` drops below this ratio after
|
|
141
|
+
* enough shift/pop operations, the deque auto-compacts.
|
|
142
|
+
* @remarks Time O(1), Space O(1)
|
|
143
|
+
* @returns Current ratio threshold. 0 means auto-compact is disabled.
|
|
144
|
+
*/
|
|
145
|
+
get autoCompactRatio(): number {
|
|
146
|
+
return this._autoCompactRatio;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Set the auto-compaction ratio.
|
|
151
|
+
* @remarks Time O(1), Space O(1)
|
|
152
|
+
* @param value - Ratio in [0,1]. 0 disables auto-compact.
|
|
153
|
+
*/
|
|
154
|
+
set autoCompactRatio(value: number) {
|
|
155
|
+
this._autoCompactRatio = value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Counter for shift/pop operations since last compaction check.
|
|
160
|
+
* Only checks ratio every `_bucketSize` operations to minimize overhead.
|
|
161
|
+
*/
|
|
162
|
+
protected _compactCounter = 0;
|
|
163
|
+
|
|
194
164
|
protected _bucketFirst = 0;
|
|
195
165
|
|
|
196
166
|
/**
|
|
@@ -279,6 +249,31 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
279
249
|
* Get the first element without removing it.
|
|
280
250
|
* @remarks Time O(1), Space O(1)
|
|
281
251
|
* @returns First element or undefined.
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
* @example
|
|
264
|
+
* // Deque peek at both ends
|
|
265
|
+
* const deque = new Deque<number>([10, 20, 30, 40, 50]);
|
|
266
|
+
*
|
|
267
|
+
* // Get first element without removing
|
|
268
|
+
* const first = deque.at(0);
|
|
269
|
+
* console.log(first); // 10;
|
|
270
|
+
*
|
|
271
|
+
* // Get last element without removing
|
|
272
|
+
* const last = deque.at(deque.length - 1);
|
|
273
|
+
* console.log(last); // 50;
|
|
274
|
+
*
|
|
275
|
+
* // Length unchanged
|
|
276
|
+
* console.log(deque.length); // 5;
|
|
282
277
|
*/
|
|
283
278
|
|
|
284
279
|
get first(): E | undefined {
|
|
@@ -290,6 +285,22 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
290
285
|
* Get the last element without removing it.
|
|
291
286
|
* @remarks Time O(1), Space O(1)
|
|
292
287
|
* @returns Last element or undefined.
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
* @example
|
|
300
|
+
* // Peek at the back element
|
|
301
|
+
* const dq = new Deque<string>(['a', 'b', 'c']);
|
|
302
|
+
* console.log(dq.last); // 'c';
|
|
303
|
+
* console.log(dq.first); // 'a';
|
|
293
304
|
*/
|
|
294
305
|
|
|
295
306
|
get last(): E | undefined {
|
|
@@ -324,6 +335,35 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
324
335
|
* @remarks Time O(1) amortized, Space O(1)
|
|
325
336
|
* @param element - Element to append.
|
|
326
337
|
* @returns True when appended.
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
* @example
|
|
350
|
+
* // basic Deque creation and push/pop operations
|
|
351
|
+
* // Create a simple Deque with initial values
|
|
352
|
+
* const deque = new Deque([1, 2, 3, 4, 5]);
|
|
353
|
+
*
|
|
354
|
+
* // Verify the deque maintains insertion order
|
|
355
|
+
* console.log([...deque]); // [1, 2, 3, 4, 5];
|
|
356
|
+
*
|
|
357
|
+
* // Check length
|
|
358
|
+
* console.log(deque.length); // 5;
|
|
359
|
+
*
|
|
360
|
+
* // Push to the end
|
|
361
|
+
* deque.push(6);
|
|
362
|
+
* console.log(deque.length); // 6;
|
|
363
|
+
*
|
|
364
|
+
* // Pop from the end
|
|
365
|
+
* const last = deque.pop();
|
|
366
|
+
* console.log(last); // 6;
|
|
327
367
|
*/
|
|
328
368
|
|
|
329
369
|
push(element: E): boolean {
|
|
@@ -349,6 +389,22 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
349
389
|
* Remove and return the last element.
|
|
350
390
|
* @remarks Time O(1), Space O(1)
|
|
351
391
|
* @returns Removed element or undefined.
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
* @example
|
|
404
|
+
* // Remove from the back
|
|
405
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
406
|
+
* console.log(dq.pop()); // 3;
|
|
407
|
+
* console.log(dq.length); // 2;
|
|
352
408
|
*/
|
|
353
409
|
|
|
354
410
|
pop(): E | undefined {
|
|
@@ -366,6 +422,7 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
366
422
|
}
|
|
367
423
|
}
|
|
368
424
|
this._length -= 1;
|
|
425
|
+
this._autoCompact();
|
|
369
426
|
return element;
|
|
370
427
|
}
|
|
371
428
|
|
|
@@ -373,6 +430,22 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
373
430
|
* Remove and return the first element.
|
|
374
431
|
* @remarks Time O(1) amortized, Space O(1)
|
|
375
432
|
* @returns Removed element or undefined.
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
* @example
|
|
445
|
+
* // Remove from the front
|
|
446
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
447
|
+
* console.log(dq.shift()); // 1;
|
|
448
|
+
* console.log(dq.length); // 2;
|
|
376
449
|
*/
|
|
377
450
|
|
|
378
451
|
shift(): E | undefined {
|
|
@@ -390,6 +463,7 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
390
463
|
}
|
|
391
464
|
}
|
|
392
465
|
this._length -= 1;
|
|
466
|
+
this._autoCompact();
|
|
393
467
|
return element;
|
|
394
468
|
}
|
|
395
469
|
|
|
@@ -398,6 +472,32 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
398
472
|
* @remarks Time O(1) amortized, Space O(1)
|
|
399
473
|
* @param element - Element to prepend.
|
|
400
474
|
* @returns True when prepended.
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
* @example
|
|
487
|
+
* // Deque shift and unshift operations
|
|
488
|
+
* const deque = new Deque<number>([20, 30, 40]);
|
|
489
|
+
*
|
|
490
|
+
* // Unshift adds to the front
|
|
491
|
+
* deque.unshift(10);
|
|
492
|
+
* console.log([...deque]); // [10, 20, 30, 40];
|
|
493
|
+
*
|
|
494
|
+
* // Shift removes from the front (O(1) complexity!)
|
|
495
|
+
* const first = deque.shift();
|
|
496
|
+
* console.log(first); // 10;
|
|
497
|
+
*
|
|
498
|
+
* // Verify remaining elements
|
|
499
|
+
* console.log([...deque]); // [20, 30, 40];
|
|
500
|
+
* console.log(deque.length); // 3;
|
|
401
501
|
*/
|
|
402
502
|
|
|
403
503
|
unshift(element: E): boolean {
|
|
@@ -461,6 +561,19 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
461
561
|
* Check whether the deque is empty.
|
|
462
562
|
* @remarks Time O(1), Space O(1)
|
|
463
563
|
* @returns True if length is 0.
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
* @example
|
|
574
|
+
* // Check if empty
|
|
575
|
+
* const dq = new Deque();
|
|
576
|
+
* console.log(dq.isEmpty()); // true;
|
|
464
577
|
*/
|
|
465
578
|
|
|
466
579
|
isEmpty(): boolean {
|
|
@@ -471,6 +584,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
471
584
|
* Remove all elements and reset structure.
|
|
472
585
|
* @remarks Time O(1), Space O(1)
|
|
473
586
|
* @returns void
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
* @example
|
|
597
|
+
* // Remove all elements
|
|
598
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
599
|
+
* dq.clear();
|
|
600
|
+
* console.log(dq.length); // 0;
|
|
474
601
|
*/
|
|
475
602
|
|
|
476
603
|
clear(): void {
|
|
@@ -485,6 +612,19 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
485
612
|
* @remarks Time O(1), Space O(1)
|
|
486
613
|
* @param pos - Zero-based position from the front.
|
|
487
614
|
* @returns Element or undefined.
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
* @example
|
|
624
|
+
* // Access by index
|
|
625
|
+
* const dq = new Deque<string>(['a', 'b', 'c']);
|
|
626
|
+
* console.log(dq.at(0)); // 'a';
|
|
627
|
+
* console.log(dq.at(2)); // 'c';
|
|
488
628
|
*/
|
|
489
629
|
|
|
490
630
|
at(pos: number): E | undefined {
|
|
@@ -672,6 +812,19 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
672
812
|
* @remarks Time O(N), Space O(1)
|
|
673
813
|
* @param element - Element to remove (using the configured equality).
|
|
674
814
|
* @returns True if an element was removed.
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
* @example
|
|
824
|
+
* // Remove element
|
|
825
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
826
|
+
* dq.delete(2);
|
|
827
|
+
* console.log(dq.length); // 2;
|
|
675
828
|
*/
|
|
676
829
|
|
|
677
830
|
delete(element: E): boolean {
|
|
@@ -725,6 +878,35 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
725
878
|
* Reverse the deque by reversing buckets and pointers.
|
|
726
879
|
* @remarks Time O(N), Space O(N)
|
|
727
880
|
* @returns This deque.
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
* @example
|
|
893
|
+
* // Deque for...of iteration and reverse
|
|
894
|
+
* const deque = new Deque<string>(['A', 'B', 'C', 'D']);
|
|
895
|
+
*
|
|
896
|
+
* // Iterate forward
|
|
897
|
+
* const forward: string[] = [];
|
|
898
|
+
* for (const item of deque) {
|
|
899
|
+
* forward.push(item);
|
|
900
|
+
* }
|
|
901
|
+
* console.log(forward); // ['A', 'B', 'C', 'D'];
|
|
902
|
+
*
|
|
903
|
+
* // Reverse the deque
|
|
904
|
+
* deque.reverse();
|
|
905
|
+
* const backward: string[] = [];
|
|
906
|
+
* for (const item of deque) {
|
|
907
|
+
* backward.push(item);
|
|
908
|
+
* }
|
|
909
|
+
* console.log(backward); // ['D', 'C', 'B', 'A'];
|
|
728
910
|
*/
|
|
729
911
|
|
|
730
912
|
reverse(): this {
|
|
@@ -768,11 +950,59 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
768
950
|
* @returns void
|
|
769
951
|
*/
|
|
770
952
|
|
|
953
|
+
/**
|
|
954
|
+
* (Protected) Trigger auto-compaction if space utilization drops below threshold.
|
|
955
|
+
* Only checks every `_bucketSize` operations to minimize hot-path overhead.
|
|
956
|
+
* Uses element-based ratio: `elements / (bucketCount * bucketSize)`.
|
|
957
|
+
*/
|
|
958
|
+
protected _autoCompact(): void {
|
|
959
|
+
if (this._autoCompactRatio <= 0 || this._bucketCount <= 1) return;
|
|
960
|
+
|
|
961
|
+
this._compactCounter++;
|
|
962
|
+
if (this._compactCounter < this._bucketSize) return;
|
|
963
|
+
this._compactCounter = 0;
|
|
964
|
+
|
|
965
|
+
const utilization = this._length / (this._bucketCount * this._bucketSize);
|
|
966
|
+
if (utilization < this._autoCompactRatio) {
|
|
967
|
+
this.shrinkToFit();
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Compact the deque by removing unused buckets.
|
|
973
|
+
* @remarks Time O(N), Space O(1)
|
|
974
|
+
* @returns True if compaction was performed (bucket count reduced).
|
|
975
|
+
*/
|
|
976
|
+
/**
|
|
977
|
+
* Compact the deque by removing unused buckets.
|
|
978
|
+
* @remarks Time O(N), Space O(1)
|
|
979
|
+
* @returns True if compaction was performed (bucket count reduced).
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
* @example
|
|
989
|
+
* // Reclaim memory
|
|
990
|
+
* const dq = new Deque<number>([1, 2, 3, 4, 5]);
|
|
991
|
+
* dq.shift();
|
|
992
|
+
* dq.shift();
|
|
993
|
+
* dq.compact();
|
|
994
|
+
* console.log(dq.length); // 3;
|
|
995
|
+
*/
|
|
996
|
+
compact(): boolean {
|
|
997
|
+
const before = this._bucketCount;
|
|
998
|
+
this.shrinkToFit();
|
|
999
|
+
return this._bucketCount < before;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
771
1002
|
shrinkToFit(): void {
|
|
772
1003
|
if (this._length === 0) return;
|
|
773
1004
|
const newBuckets = [] as E[][];
|
|
774
|
-
if (this._bucketFirst
|
|
775
|
-
else if (this._bucketFirst < this._bucketLast) {
|
|
1005
|
+
if (this._bucketFirst <= this._bucketLast) {
|
|
776
1006
|
for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
|
|
777
1007
|
newBuckets.push(this._buckets[i]);
|
|
778
1008
|
}
|
|
@@ -787,12 +1017,30 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
787
1017
|
this._bucketFirst = 0;
|
|
788
1018
|
this._bucketLast = newBuckets.length - 1;
|
|
789
1019
|
this._buckets = newBuckets;
|
|
1020
|
+
this._bucketCount = newBuckets.length;
|
|
1021
|
+
this._compactCounter = 0;
|
|
790
1022
|
}
|
|
791
1023
|
|
|
792
1024
|
/**
|
|
793
1025
|
* Deep clone this deque, preserving options.
|
|
794
1026
|
* @remarks Time O(N), Space O(N)
|
|
795
1027
|
* @returns A new deque with the same content and options.
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
* @example
|
|
1038
|
+
* // Create independent copy
|
|
1039
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
1040
|
+
* const copy = dq.clone();
|
|
1041
|
+
* copy.pop();
|
|
1042
|
+
* console.log(dq.length); // 3;
|
|
1043
|
+
* console.log(copy.length); // 2;
|
|
796
1044
|
*/
|
|
797
1045
|
|
|
798
1046
|
clone(): this {
|
|
@@ -809,6 +1057,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
809
1057
|
* @param predicate - Predicate (value, index, deque) → boolean to keep element.
|
|
810
1058
|
* @param [thisArg] - Value for `this` inside the predicate.
|
|
811
1059
|
* @returns A new deque with kept elements.
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
* @example
|
|
1070
|
+
* // Filter elements
|
|
1071
|
+
* const dq = new Deque<number>([1, 2, 3, 4]);
|
|
1072
|
+
* const result = dq.filter(x => x > 2);
|
|
1073
|
+
* console.log(result.length); // 2;
|
|
812
1074
|
*/
|
|
813
1075
|
|
|
814
1076
|
filter(predicate: ElementCallback<E, R, boolean>, thisArg?: any): this {
|
|
@@ -850,6 +1112,19 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
850
1112
|
* @param [options] - Options for the output deque (e.g., bucketSize, toElementFn, maxLen).
|
|
851
1113
|
* @param [thisArg] - Value for `this` inside the callback.
|
|
852
1114
|
* @returns A new Deque with mapped elements.
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
* @example
|
|
1124
|
+
* // Transform elements
|
|
1125
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
1126
|
+
* const result = dq.map(x => x * 10);
|
|
1127
|
+
* console.log(result.toArray()); // [10, 20, 30];
|
|
853
1128
|
*/
|
|
854
1129
|
|
|
855
1130
|
map<EM, RM>(
|