data-structure-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/CHANGELOG.md +22 -1
- package/README.md +34 -1
- package/dist/cjs/index.cjs +10639 -2151
- package/dist/cjs-legacy/index.cjs +10694 -2195
- package/dist/esm/index.mjs +10639 -2150
- package/dist/esm-legacy/index.mjs +10694 -2194
- 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/data-structure-typed.js +10725 -2221
- package/dist/umd/data-structure-typed.min.js +4 -2
- package/package.json +5 -4
- 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 +146 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +317 -247
- package/src/data-structures/binary-tree/binary-tree.ts +567 -121
- package/src/data-structures/binary-tree/bst.ts +370 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +328 -96
- package/src/data-structures/binary-tree/segment-tree.ts +378 -248
- package/src/data-structures/binary-tree/tree-map.ts +1411 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1218 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +959 -69
- package/src/data-structures/binary-tree/tree-set.ts +1257 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +233 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +308 -59
- package/src/data-structures/hash/hash-map.ts +254 -79
- package/src/data-structures/heap/heap.ts +305 -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 +303 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +293 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +707 -90
- package/src/data-structures/matrix/matrix.ts +433 -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 +358 -68
- package/src/data-structures/queue/queue.ts +223 -42
- package/src/data-structures/stack/stack.ts +184 -32
- package/src/data-structures/trie/trie.ts +227 -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
|
@@ -15,6 +15,66 @@ import { PriorityQueue } from './priority-queue';
|
|
|
15
15
|
* @template E Element type stored in the queue.
|
|
16
16
|
* @template R Extra record/metadata associated with each element.
|
|
17
17
|
* @example
|
|
18
|
+
* // Shortest job first scheduling
|
|
19
|
+
* const jobs = new MinPriorityQueue<number>();
|
|
20
|
+
*
|
|
21
|
+
* jobs.add(8); // 8 seconds
|
|
22
|
+
* jobs.add(2); // 2 seconds
|
|
23
|
+
* jobs.add(5); // 5 seconds
|
|
24
|
+
* jobs.add(1); // 1 second
|
|
25
|
+
*
|
|
26
|
+
* // Shortest job first
|
|
27
|
+
* console.log(jobs.poll()); // 1;
|
|
28
|
+
* console.log(jobs.poll()); // 2;
|
|
29
|
+
* console.log(jobs.poll()); // 5;
|
|
30
|
+
* console.log(jobs.poll()); // 8;
|
|
31
|
+
* @example
|
|
32
|
+
* // Event-driven simulation with timestamps
|
|
33
|
+
* interface Event {
|
|
34
|
+
* time: number;
|
|
35
|
+
* action: string;
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* const timeline = new MinPriorityQueue<Event>([], {
|
|
39
|
+
* comparator: (a, b) => a.time - b.time
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* timeline.add({ time: 300, action: 'Timeout' });
|
|
43
|
+
* timeline.add({ time: 100, action: 'Request received' });
|
|
44
|
+
* timeline.add({ time: 200, action: 'Processing done' });
|
|
45
|
+
* timeline.add({ time: 150, action: 'Cache hit' });
|
|
46
|
+
*
|
|
47
|
+
* const order = [];
|
|
48
|
+
* while (timeline.size > 0) {
|
|
49
|
+
* order.push(timeline.poll()!.action);
|
|
50
|
+
* }
|
|
51
|
+
* console.log(order); // [
|
|
52
|
+
* // 'Request received',
|
|
53
|
+
* // 'Cache hit',
|
|
54
|
+
* // 'Processing done',
|
|
55
|
+
* // 'Timeout'
|
|
56
|
+
* // ];
|
|
57
|
+
* @example
|
|
58
|
+
* // Huffman coding frequency selection
|
|
59
|
+
* // Character frequencies for Huffman tree building
|
|
60
|
+
* const freq = new MinPriorityQueue<[number, string]>([], {
|
|
61
|
+
* comparator: (a, b) => a[0] - b[0]
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* freq.add([5, 'a']);
|
|
65
|
+
* freq.add([9, 'b']);
|
|
66
|
+
* freq.add([12, 'c']);
|
|
67
|
+
* freq.add([2, 'd']);
|
|
68
|
+
*
|
|
69
|
+
* // Always pick two lowest frequencies
|
|
70
|
+
* const first = freq.poll()!;
|
|
71
|
+
* const second = freq.poll()!;
|
|
72
|
+
* console.log(first[1]); // 'd'; // freq 2
|
|
73
|
+
* console.log(second[1]); // 'a'; // freq 5
|
|
74
|
+
*
|
|
75
|
+
* // Combined node goes back
|
|
76
|
+
* freq.add([first[0] + second[0], first[1] + second[1]]);
|
|
77
|
+
* console.log(freq.peek()![0]); // 7;
|
|
18
78
|
*/
|
|
19
79
|
export class MinPriorityQueue<E = any, R = any> extends PriorityQueue<E, R> {
|
|
20
80
|
/**
|
|
@@ -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,32 @@ 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
|
+
|
|
264
|
+
* @example
|
|
265
|
+
* // Deque peek at both ends
|
|
266
|
+
* const deque = new Deque<number>([10, 20, 30, 40, 50]);
|
|
267
|
+
*
|
|
268
|
+
* // Get first element without removing
|
|
269
|
+
* const first = deque.at(0);
|
|
270
|
+
* console.log(first); // 10;
|
|
271
|
+
*
|
|
272
|
+
* // Get last element without removing
|
|
273
|
+
* const last = deque.at(deque.length - 1);
|
|
274
|
+
* console.log(last); // 50;
|
|
275
|
+
*
|
|
276
|
+
* // Length unchanged
|
|
277
|
+
* console.log(deque.length); // 5;
|
|
282
278
|
*/
|
|
283
279
|
|
|
284
280
|
get first(): E | undefined {
|
|
@@ -290,6 +286,23 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
290
286
|
* Get the last element without removing it.
|
|
291
287
|
* @remarks Time O(1), Space O(1)
|
|
292
288
|
* @returns Last element or undefined.
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
* @example
|
|
302
|
+
* // Peek at the back element
|
|
303
|
+
* const dq = new Deque<string>(['a', 'b', 'c']);
|
|
304
|
+
* console.log(dq.last); // 'c';
|
|
305
|
+
* console.log(dq.first); // 'a';
|
|
293
306
|
*/
|
|
294
307
|
|
|
295
308
|
get last(): E | undefined {
|
|
@@ -324,6 +337,36 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
324
337
|
* @remarks Time O(1) amortized, Space O(1)
|
|
325
338
|
* @param element - Element to append.
|
|
326
339
|
* @returns True when appended.
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
* @example
|
|
353
|
+
* // basic Deque creation and push/pop operations
|
|
354
|
+
* // Create a simple Deque with initial values
|
|
355
|
+
* const deque = new Deque([1, 2, 3, 4, 5]);
|
|
356
|
+
*
|
|
357
|
+
* // Verify the deque maintains insertion order
|
|
358
|
+
* console.log([...deque]); // [1, 2, 3, 4, 5];
|
|
359
|
+
*
|
|
360
|
+
* // Check length
|
|
361
|
+
* console.log(deque.length); // 5;
|
|
362
|
+
*
|
|
363
|
+
* // Push to the end
|
|
364
|
+
* deque.push(6);
|
|
365
|
+
* console.log(deque.length); // 6;
|
|
366
|
+
*
|
|
367
|
+
* // Pop from the end
|
|
368
|
+
* const last = deque.pop();
|
|
369
|
+
* console.log(last); // 6;
|
|
327
370
|
*/
|
|
328
371
|
|
|
329
372
|
push(element: E): boolean {
|
|
@@ -349,6 +392,23 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
349
392
|
* Remove and return the last element.
|
|
350
393
|
* @remarks Time O(1), Space O(1)
|
|
351
394
|
* @returns Removed element or undefined.
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
* @example
|
|
408
|
+
* // Remove from the back
|
|
409
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
410
|
+
* console.log(dq.pop()); // 3;
|
|
411
|
+
* console.log(dq.length); // 2;
|
|
352
412
|
*/
|
|
353
413
|
|
|
354
414
|
pop(): E | undefined {
|
|
@@ -366,6 +426,7 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
366
426
|
}
|
|
367
427
|
}
|
|
368
428
|
this._length -= 1;
|
|
429
|
+
this._autoCompact();
|
|
369
430
|
return element;
|
|
370
431
|
}
|
|
371
432
|
|
|
@@ -373,6 +434,23 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
373
434
|
* Remove and return the first element.
|
|
374
435
|
* @remarks Time O(1) amortized, Space O(1)
|
|
375
436
|
* @returns Removed element or undefined.
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
* @example
|
|
450
|
+
* // Remove from the front
|
|
451
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
452
|
+
* console.log(dq.shift()); // 1;
|
|
453
|
+
* console.log(dq.length); // 2;
|
|
376
454
|
*/
|
|
377
455
|
|
|
378
456
|
shift(): E | undefined {
|
|
@@ -390,6 +468,7 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
390
468
|
}
|
|
391
469
|
}
|
|
392
470
|
this._length -= 1;
|
|
471
|
+
this._autoCompact();
|
|
393
472
|
return element;
|
|
394
473
|
}
|
|
395
474
|
|
|
@@ -398,6 +477,33 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
398
477
|
* @remarks Time O(1) amortized, Space O(1)
|
|
399
478
|
* @param element - Element to prepend.
|
|
400
479
|
* @returns True when prepended.
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
* @example
|
|
493
|
+
* // Deque shift and unshift operations
|
|
494
|
+
* const deque = new Deque<number>([20, 30, 40]);
|
|
495
|
+
*
|
|
496
|
+
* // Unshift adds to the front
|
|
497
|
+
* deque.unshift(10);
|
|
498
|
+
* console.log([...deque]); // [10, 20, 30, 40];
|
|
499
|
+
*
|
|
500
|
+
* // Shift removes from the front (O(1) complexity!)
|
|
501
|
+
* const first = deque.shift();
|
|
502
|
+
* console.log(first); // 10;
|
|
503
|
+
*
|
|
504
|
+
* // Verify remaining elements
|
|
505
|
+
* console.log([...deque]); // [20, 30, 40];
|
|
506
|
+
* console.log(deque.length); // 3;
|
|
401
507
|
*/
|
|
402
508
|
|
|
403
509
|
unshift(element: E): boolean {
|
|
@@ -461,6 +567,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
461
567
|
* Check whether the deque is empty.
|
|
462
568
|
* @remarks Time O(1), Space O(1)
|
|
463
569
|
* @returns True if length is 0.
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
* @example
|
|
581
|
+
* // Check if empty
|
|
582
|
+
* const dq = new Deque();
|
|
583
|
+
* console.log(dq.isEmpty()); // true;
|
|
464
584
|
*/
|
|
465
585
|
|
|
466
586
|
isEmpty(): boolean {
|
|
@@ -471,6 +591,21 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
471
591
|
* Remove all elements and reset structure.
|
|
472
592
|
* @remarks Time O(1), Space O(1)
|
|
473
593
|
* @returns void
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
* @example
|
|
605
|
+
* // Remove all elements
|
|
606
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
607
|
+
* dq.clear();
|
|
608
|
+
* console.log(dq.length); // 0;
|
|
474
609
|
*/
|
|
475
610
|
|
|
476
611
|
clear(): void {
|
|
@@ -485,6 +620,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
485
620
|
* @remarks Time O(1), Space O(1)
|
|
486
621
|
* @param pos - Zero-based position from the front.
|
|
487
622
|
* @returns Element or undefined.
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
* @example
|
|
633
|
+
* // Access by index
|
|
634
|
+
* const dq = new Deque<string>(['a', 'b', 'c']);
|
|
635
|
+
* console.log(dq.at(0)); // 'a';
|
|
636
|
+
* console.log(dq.at(2)); // 'c';
|
|
488
637
|
*/
|
|
489
638
|
|
|
490
639
|
at(pos: number): E | undefined {
|
|
@@ -672,6 +821,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
672
821
|
* @remarks Time O(N), Space O(1)
|
|
673
822
|
* @param element - Element to remove (using the configured equality).
|
|
674
823
|
* @returns True if an element was removed.
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
* @example
|
|
834
|
+
* // Remove element
|
|
835
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
836
|
+
* dq.delete(2);
|
|
837
|
+
* console.log(dq.length); // 2;
|
|
675
838
|
*/
|
|
676
839
|
|
|
677
840
|
delete(element: E): boolean {
|
|
@@ -725,6 +888,36 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
725
888
|
* Reverse the deque by reversing buckets and pointers.
|
|
726
889
|
* @remarks Time O(N), Space O(N)
|
|
727
890
|
* @returns This deque.
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
* @example
|
|
904
|
+
* // Deque for...of iteration and reverse
|
|
905
|
+
* const deque = new Deque<string>(['A', 'B', 'C', 'D']);
|
|
906
|
+
*
|
|
907
|
+
* // Iterate forward
|
|
908
|
+
* const forward: string[] = [];
|
|
909
|
+
* for (const item of deque) {
|
|
910
|
+
* forward.push(item);
|
|
911
|
+
* }
|
|
912
|
+
* console.log(forward); // ['A', 'B', 'C', 'D'];
|
|
913
|
+
*
|
|
914
|
+
* // Reverse the deque
|
|
915
|
+
* deque.reverse();
|
|
916
|
+
* const backward: string[] = [];
|
|
917
|
+
* for (const item of deque) {
|
|
918
|
+
* backward.push(item);
|
|
919
|
+
* }
|
|
920
|
+
* console.log(backward); // ['D', 'C', 'B', 'A'];
|
|
728
921
|
*/
|
|
729
922
|
|
|
730
923
|
reverse(): this {
|
|
@@ -768,11 +961,60 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
768
961
|
* @returns void
|
|
769
962
|
*/
|
|
770
963
|
|
|
964
|
+
/**
|
|
965
|
+
* (Protected) Trigger auto-compaction if space utilization drops below threshold.
|
|
966
|
+
* Only checks every `_bucketSize` operations to minimize hot-path overhead.
|
|
967
|
+
* Uses element-based ratio: `elements / (bucketCount * bucketSize)`.
|
|
968
|
+
*/
|
|
969
|
+
protected _autoCompact(): void {
|
|
970
|
+
if (this._autoCompactRatio <= 0 || this._bucketCount <= 1) return;
|
|
971
|
+
|
|
972
|
+
this._compactCounter++;
|
|
973
|
+
if (this._compactCounter < this._bucketSize) return;
|
|
974
|
+
this._compactCounter = 0;
|
|
975
|
+
|
|
976
|
+
const utilization = this._length / (this._bucketCount * this._bucketSize);
|
|
977
|
+
if (utilization < this._autoCompactRatio) {
|
|
978
|
+
this.shrinkToFit();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Compact the deque by removing unused buckets.
|
|
984
|
+
* @remarks Time O(N), Space O(1)
|
|
985
|
+
* @returns True if compaction was performed (bucket count reduced).
|
|
986
|
+
*/
|
|
987
|
+
/**
|
|
988
|
+
* Compact the deque by removing unused buckets.
|
|
989
|
+
* @remarks Time O(N), Space O(1)
|
|
990
|
+
* @returns True if compaction was performed (bucket count reduced).
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
* @example
|
|
1001
|
+
* // Reclaim memory
|
|
1002
|
+
* const dq = new Deque<number>([1, 2, 3, 4, 5]);
|
|
1003
|
+
* dq.shift();
|
|
1004
|
+
* dq.shift();
|
|
1005
|
+
* dq.compact();
|
|
1006
|
+
* console.log(dq.length); // 3;
|
|
1007
|
+
*/
|
|
1008
|
+
compact(): boolean {
|
|
1009
|
+
const before = this._bucketCount;
|
|
1010
|
+
this.shrinkToFit();
|
|
1011
|
+
return this._bucketCount < before;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
771
1014
|
shrinkToFit(): void {
|
|
772
1015
|
if (this._length === 0) return;
|
|
773
1016
|
const newBuckets = [] as E[][];
|
|
774
|
-
if (this._bucketFirst
|
|
775
|
-
else if (this._bucketFirst < this._bucketLast) {
|
|
1017
|
+
if (this._bucketFirst <= this._bucketLast) {
|
|
776
1018
|
for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
|
|
777
1019
|
newBuckets.push(this._buckets[i]);
|
|
778
1020
|
}
|
|
@@ -787,12 +1029,31 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
787
1029
|
this._bucketFirst = 0;
|
|
788
1030
|
this._bucketLast = newBuckets.length - 1;
|
|
789
1031
|
this._buckets = newBuckets;
|
|
1032
|
+
this._bucketCount = newBuckets.length;
|
|
1033
|
+
this._compactCounter = 0;
|
|
790
1034
|
}
|
|
791
1035
|
|
|
792
1036
|
/**
|
|
793
1037
|
* Deep clone this deque, preserving options.
|
|
794
1038
|
* @remarks Time O(N), Space O(N)
|
|
795
1039
|
* @returns A new deque with the same content and options.
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
* @example
|
|
1051
|
+
* // Create independent copy
|
|
1052
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
1053
|
+
* const copy = dq.clone();
|
|
1054
|
+
* copy.pop();
|
|
1055
|
+
* console.log(dq.length); // 3;
|
|
1056
|
+
* console.log(copy.length); // 2;
|
|
796
1057
|
*/
|
|
797
1058
|
|
|
798
1059
|
clone(): this {
|
|
@@ -809,6 +1070,21 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
809
1070
|
* @param predicate - Predicate (value, index, deque) → boolean to keep element.
|
|
810
1071
|
* @param [thisArg] - Value for `this` inside the predicate.
|
|
811
1072
|
* @returns A new deque with kept elements.
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
* @example
|
|
1084
|
+
* // Filter elements
|
|
1085
|
+
* const dq = new Deque<number>([1, 2, 3, 4]);
|
|
1086
|
+
* const result = dq.filter(x => x > 2);
|
|
1087
|
+
* console.log(result.length); // 2;
|
|
812
1088
|
*/
|
|
813
1089
|
|
|
814
1090
|
filter(predicate: ElementCallback<E, R, boolean>, thisArg?: any): this {
|
|
@@ -850,6 +1126,20 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
|
|
|
850
1126
|
* @param [options] - Options for the output deque (e.g., bucketSize, toElementFn, maxLen).
|
|
851
1127
|
* @param [thisArg] - Value for `this` inside the callback.
|
|
852
1128
|
* @returns A new Deque with mapped elements.
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
* @example
|
|
1139
|
+
* // Transform elements
|
|
1140
|
+
* const dq = new Deque<number>([1, 2, 3]);
|
|
1141
|
+
* const result = dq.map(x => x * 10);
|
|
1142
|
+
* console.log(result.toArray()); // [10, 20, 30];
|
|
853
1143
|
*/
|
|
854
1144
|
|
|
855
1145
|
map<EM, RM>(
|