data-structure-typed 2.6.0 → 2.6.1
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/.github/workflows/ci.yml +7 -2
- package/.github/workflows/release-package.yml +9 -2
- package/docs-site-docusaurus/docs/api/classes/AVLTree.md +108 -108
- package/docs-site-docusaurus/docs/api/classes/BST.md +101 -101
- package/docs-site-docusaurus/docs/api/classes/BinaryIndexedTree.md +13 -13
- package/docs-site-docusaurus/docs/api/classes/BinaryTree.md +66 -66
- package/docs-site-docusaurus/docs/api/classes/Deque.md +235 -51
- package/docs-site-docusaurus/docs/api/classes/DirectedGraph.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/DoublyLinkedList.md +231 -67
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeap.md +9 -9
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeapNode.md +1 -1
- package/docs-site-docusaurus/docs/api/classes/HashMap.md +14 -14
- package/docs-site-docusaurus/docs/api/classes/Heap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/IterableElementBase.md +83 -13
- package/docs-site-docusaurus/docs/api/classes/LinearBase.md +124 -20
- package/docs-site-docusaurus/docs/api/classes/LinearLinkedBase.md +140 -32
- package/docs-site-docusaurus/docs/api/classes/LinkedHashMap.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/LinkedListQueue.md +159 -51
- package/docs-site-docusaurus/docs/api/classes/MapGraph.md +20 -20
- package/docs-site-docusaurus/docs/api/classes/Matrix.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/MaxHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MaxPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/PriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/Queue.md +142 -34
- package/docs-site-docusaurus/docs/api/classes/RedBlackTree.md +117 -117
- package/docs-site-docusaurus/docs/api/classes/SegmentTree.md +8 -8
- package/docs-site-docusaurus/docs/api/classes/SinglyLinkedList.md +158 -50
- package/docs-site-docusaurus/docs/api/classes/SkipList.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/Stack.md +108 -26
- package/docs-site-docusaurus/docs/api/classes/TreeMap.md +33 -33
- package/docs-site-docusaurus/docs/api/classes/TreeMultiMap.md +75 -39
- package/docs-site-docusaurus/docs/api/classes/TreeSet.md +301 -39
- package/docs-site-docusaurus/docs/api/classes/Trie.md +110 -28
- package/docs-site-docusaurus/docs/api/classes/UndirectedGraph.md +20 -20
- package/package.json +45 -46
- package/src/common/error.ts +15 -32
- package/src/common/index.ts +0 -3
- package/src/data-structures/base/iterable-element-base.ts +0 -3
- package/src/data-structures/base/linear-base.ts +2 -36
- package/src/data-structures/binary-tree/avl-tree.ts +31 -529
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +47 -572
- package/src/data-structures/binary-tree/binary-tree.ts +326 -1311
- package/src/data-structures/binary-tree/bst.ts +158 -1082
- package/src/data-structures/binary-tree/red-black-tree.ts +451 -1290
- package/src/data-structures/binary-tree/segment-tree.ts +73 -351
- package/src/data-structures/binary-tree/tree-map.ts +462 -5124
- package/src/data-structures/binary-tree/tree-multi-map.ts +302 -4914
- package/src/data-structures/binary-tree/tree-multi-set.ts +284 -3972
- package/src/data-structures/binary-tree/tree-set.ts +338 -4836
- package/src/data-structures/graph/abstract-graph.ts +98 -167
- package/src/data-structures/graph/directed-graph.ts +137 -562
- package/src/data-structures/graph/map-graph.ts +0 -3
- package/src/data-structures/graph/undirected-graph.ts +132 -511
- package/src/data-structures/hash/hash-map.ts +154 -582
- package/src/data-structures/heap/heap.ts +200 -795
- package/src/data-structures/linked-list/doubly-linked-list.ts +121 -865
- package/src/data-structures/linked-list/singly-linked-list.ts +122 -794
- package/src/data-structures/linked-list/skip-linked-list.ts +211 -918
- package/src/data-structures/matrix/matrix.ts +179 -518
- package/src/data-structures/matrix/navigator.ts +0 -1
- package/src/data-structures/priority-queue/max-priority-queue.ts +1 -6
- package/src/data-structures/priority-queue/min-priority-queue.ts +6 -11
- package/src/data-structures/priority-queue/priority-queue.ts +1 -2
- package/src/data-structures/queue/deque.ts +214 -882
- package/src/data-structures/queue/queue.ts +102 -625
- package/src/data-structures/stack/stack.ts +76 -505
- package/src/data-structures/trie/trie.ts +98 -628
- package/src/types/common.ts +0 -10
- package/src/types/data-structures/binary-tree/bst.ts +0 -7
- package/src/types/data-structures/binary-tree/red-black-tree.ts +0 -1
- package/src/types/data-structures/graph/abstract-graph.ts +0 -2
- package/src/types/data-structures/hash/hash-map.ts +0 -3
- package/src/types/data-structures/hash/index.ts +0 -1
- package/src/types/data-structures/matrix/navigator.ts +0 -2
- package/src/types/utils/utils.ts +0 -7
- package/src/types/utils/validate-type.ts +0 -7
- package/src/utils/number.ts +0 -2
- package/src/utils/utils.ts +0 -5
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
8
|
import type { Comparator, EntryCallback } from '../../types';
|
|
10
9
|
import { ERR, raise } from '../../common';
|
|
11
10
|
import { IterableEntryBase } from '../base';
|
|
@@ -28,13 +27,11 @@ export type SkipListOptions<K, V, R = [K, V]> = {
|
|
|
28
27
|
maxLevel?: number;
|
|
29
28
|
probability?: number;
|
|
30
29
|
};
|
|
31
|
-
|
|
32
30
|
export type SkipListRangeOptions = {
|
|
33
31
|
lowInclusive?: boolean;
|
|
34
32
|
highInclusive?: boolean;
|
|
35
33
|
};
|
|
36
34
|
|
|
37
|
-
|
|
38
35
|
/**
|
|
39
36
|
* SkipList — a probabilistic sorted key-value container.
|
|
40
37
|
*
|
|
@@ -47,24 +44,20 @@ export type SkipListRangeOptions = {
|
|
|
47
44
|
* expect(() => sl.print()).not.toThrow();
|
|
48
45
|
*/
|
|
49
46
|
export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V | undefined> {
|
|
47
|
+
// ─── Internal state ──────────────────────────────────────────
|
|
48
|
+
protected _head: SkipListNode<K, V>;
|
|
49
|
+
protected _level: number = 0;
|
|
50
50
|
readonly #comparator: Comparator<K>;
|
|
51
51
|
readonly #isDefaultComparator: boolean;
|
|
52
52
|
|
|
53
|
-
constructor(
|
|
54
|
-
entries: Iterable<R> | Iterable<[K, V | undefined]> = [],
|
|
55
|
-
options: SkipListOptions<K, V, R> = {}
|
|
56
|
-
) {
|
|
53
|
+
constructor(entries: Iterable<R> | Iterable<[K, V | undefined]> = [], options: SkipListOptions<K, V, R> = {}) {
|
|
57
54
|
super();
|
|
58
55
|
const { comparator, toEntryFn, maxLevel, probability } = options;
|
|
59
|
-
|
|
60
56
|
if (typeof maxLevel === 'number' && maxLevel > 0) this._maxLevel = maxLevel;
|
|
61
57
|
if (typeof probability === 'number' && probability > 0 && probability < 1) this._probability = probability;
|
|
62
|
-
|
|
63
58
|
this.#isDefaultComparator = comparator === undefined;
|
|
64
59
|
this.#comparator = comparator ?? SkipList.createDefaultComparator<K>();
|
|
65
|
-
|
|
66
60
|
this._head = new SkipListNode<K, V>(undefined as K, undefined as V, this._maxLevel);
|
|
67
|
-
|
|
68
61
|
for (const item of entries) {
|
|
69
62
|
let k: K;
|
|
70
63
|
let v: V | undefined;
|
|
@@ -80,6 +73,29 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
80
73
|
}
|
|
81
74
|
}
|
|
82
75
|
|
|
76
|
+
protected _size: number = 0;
|
|
77
|
+
|
|
78
|
+
// ─── Size & lifecycle ────────────────────────────────────────
|
|
79
|
+
get size(): number {
|
|
80
|
+
return this._size;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
protected _maxLevel: number = 16;
|
|
84
|
+
|
|
85
|
+
get maxLevel(): number {
|
|
86
|
+
return this._maxLevel;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected _probability: number = 0.5;
|
|
90
|
+
|
|
91
|
+
get probability(): number {
|
|
92
|
+
return this._probability;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get comparator(): Comparator<K> {
|
|
96
|
+
return this.#comparator;
|
|
97
|
+
}
|
|
98
|
+
|
|
83
99
|
/**
|
|
84
100
|
* Creates a default comparator supporting number, string, Date, and bigint.
|
|
85
101
|
*/
|
|
@@ -105,132 +121,27 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
105
121
|
};
|
|
106
122
|
}
|
|
107
123
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
protected _head: SkipListNode<K, V>;
|
|
111
|
-
|
|
112
|
-
protected _level: number = 0;
|
|
113
|
-
|
|
114
|
-
protected _size: number = 0;
|
|
115
|
-
|
|
116
|
-
protected _maxLevel: number = 16;
|
|
117
|
-
|
|
118
|
-
protected _probability: number = 0.5;
|
|
119
|
-
|
|
120
|
-
// ─── Size & lifecycle ────────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
get size(): number {
|
|
123
|
-
return this._size;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get maxLevel(): number {
|
|
127
|
-
return this._maxLevel;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
get probability(): number {
|
|
131
|
-
return this._probability;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
get comparator(): Comparator<K> {
|
|
135
|
-
return this.#comparator;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
124
|
+
/**
|
|
139
125
|
* Check if empty
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
* @example
|
|
180
|
-
* // Check if empty
|
|
181
|
-
* const sl = new SkipList<number, string>();
|
|
182
|
-
* console.log(sl.isEmpty()); // true;
|
|
126
|
+
* @example
|
|
127
|
+
* // Check if empty
|
|
128
|
+
* const sl = new SkipList<number, string>();
|
|
129
|
+
* console.log(sl.isEmpty()); // true;
|
|
183
130
|
*/
|
|
184
131
|
isEmpty(): boolean {
|
|
185
132
|
return this._size === 0;
|
|
186
133
|
}
|
|
187
134
|
|
|
188
|
-
|
|
135
|
+
/**
|
|
189
136
|
* Remove all entries
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
* @example
|
|
230
|
-
* // Remove all entries
|
|
231
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
232
|
-
* sl.clear();
|
|
233
|
-
* console.log(sl.isEmpty()); // true;
|
|
137
|
+
* @example
|
|
138
|
+
* // Remove all entries
|
|
139
|
+
* const sl = new SkipList<number, string>([
|
|
140
|
+
* [1, 'a'],
|
|
141
|
+
* [2, 'b']
|
|
142
|
+
* ]);
|
|
143
|
+
* sl.clear();
|
|
144
|
+
* console.log(sl.isEmpty()); // true;
|
|
234
145
|
*/
|
|
235
146
|
clear(): void {
|
|
236
147
|
this._head = new SkipListNode<K, V>(undefined as K, undefined as V, this._maxLevel);
|
|
@@ -238,53 +149,17 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
238
149
|
this._size = 0;
|
|
239
150
|
}
|
|
240
151
|
|
|
241
|
-
|
|
152
|
+
/**
|
|
242
153
|
* Create independent copy
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
* @example
|
|
283
|
-
* // Create independent copy
|
|
284
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
285
|
-
* const copy = sl.clone();
|
|
286
|
-
* copy.delete(1);
|
|
287
|
-
* console.log(sl.has(1)); // true;
|
|
154
|
+
* @example
|
|
155
|
+
* // Create independent copy
|
|
156
|
+
* const sl = new SkipList<number, string>([
|
|
157
|
+
* [1, 'a'],
|
|
158
|
+
* [2, 'b']
|
|
159
|
+
* ]);
|
|
160
|
+
* const copy = sl.clone();
|
|
161
|
+
* copy.delete(1);
|
|
162
|
+
* console.log(sl.has(1)); // true;
|
|
288
163
|
*/
|
|
289
164
|
clone(): this {
|
|
290
165
|
return new SkipList<K, V, R>(this as Iterable<[K, V | undefined]>, {
|
|
@@ -299,91 +174,44 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
299
174
|
/**
|
|
300
175
|
* Insert or update a key-value pair. Returns `this` for chaining.
|
|
301
176
|
* Unique keys only — if key exists, value is updated in place.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
* @example
|
|
345
|
-
* // In-memory sorted key-value store
|
|
346
|
-
* const store = new SkipList<number, string>();
|
|
347
|
-
*
|
|
348
|
-
* store.set(3, 'three');
|
|
349
|
-
* store.set(1, 'one');
|
|
350
|
-
* store.set(5, 'five');
|
|
351
|
-
* store.set(2, 'two');
|
|
352
|
-
*
|
|
353
|
-
* console.log(store.get(3)); // 'three';
|
|
354
|
-
* console.log(store.get(1)); // 'one';
|
|
355
|
-
* console.log(store.get(5)); // 'five';
|
|
356
|
-
*
|
|
357
|
-
* // Update existing key
|
|
358
|
-
* store.set(3, 'THREE');
|
|
359
|
-
* console.log(store.get(3)); // 'THREE';
|
|
177
|
+
* @example
|
|
178
|
+
* // In-memory sorted key-value store
|
|
179
|
+
* const store = new SkipList<number, string>();
|
|
180
|
+
*
|
|
181
|
+
* store.set(3, 'three');
|
|
182
|
+
* store.set(1, 'one');
|
|
183
|
+
* store.set(5, 'five');
|
|
184
|
+
* store.set(2, 'two');
|
|
185
|
+
*
|
|
186
|
+
* console.log(store.get(3)); // 'three';
|
|
187
|
+
* console.log(store.get(1)); // 'one';
|
|
188
|
+
* console.log(store.get(5)); // 'five';
|
|
189
|
+
*
|
|
190
|
+
* // Update existing key
|
|
191
|
+
* store.set(3, 'THREE');
|
|
192
|
+
* console.log(store.get(3)); // 'THREE';
|
|
360
193
|
*/
|
|
361
194
|
set(key: K, value: V): this {
|
|
362
195
|
const cmp = this.#comparator;
|
|
363
196
|
const update = this._findUpdate(key);
|
|
364
|
-
|
|
365
197
|
// If key already exists, update value in place
|
|
366
198
|
const existing = update[0].forward[0];
|
|
367
199
|
if (existing && cmp(existing.key, key) === 0) {
|
|
368
200
|
existing.value = value;
|
|
369
201
|
return this;
|
|
370
202
|
}
|
|
371
|
-
|
|
372
203
|
const newLevel = this._randomLevel();
|
|
373
204
|
const newNode = new SkipListNode(key, value, newLevel);
|
|
374
|
-
|
|
375
205
|
if (newLevel > this._level) {
|
|
376
206
|
for (let i = this._level; i < newLevel; i++) {
|
|
377
207
|
update[i] = this._head;
|
|
378
208
|
}
|
|
379
209
|
this._level = newLevel;
|
|
380
210
|
}
|
|
381
|
-
|
|
382
211
|
for (let i = 0; i < newLevel; i++) {
|
|
383
212
|
newNode.forward[i] = update[i].forward[i];
|
|
384
213
|
update[i].forward[i] = newNode;
|
|
385
214
|
}
|
|
386
|
-
|
|
387
215
|
this._size++;
|
|
388
216
|
return this;
|
|
389
217
|
}
|
|
@@ -391,68 +219,26 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
391
219
|
/**
|
|
392
220
|
* Get the value for a key, or `undefined` if not found.
|
|
393
221
|
* Overrides base O(n) with O(log n) skip-list search.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
* @example
|
|
437
|
-
* // Building a sorted index
|
|
438
|
-
* type Product = { id: number; name: string; price: number };
|
|
439
|
-
* const products: Product[] = [
|
|
440
|
-
* { id: 1, name: 'Widget', price: 25 },
|
|
441
|
-
* { id: 2, name: 'Gadget', price: 50 },
|
|
442
|
-
* { id: 3, name: 'Doohickey', price: 15 }
|
|
443
|
-
* ];
|
|
444
|
-
*
|
|
445
|
-
* const index = new SkipList<number, Product, Product>(products, {
|
|
446
|
-
* toEntryFn: (p: Product) => [p.price, p]
|
|
447
|
-
* });
|
|
448
|
-
*
|
|
449
|
-
* // Iterate in sorted order by price
|
|
450
|
-
* const names = [...index.values()].map(p => p!.name);
|
|
451
|
-
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
452
|
-
*
|
|
453
|
-
* // Range search: products between $20 and $60
|
|
454
|
-
* const range = index.rangeSearch([20, 60]);
|
|
455
|
-
* console.log(range.map(([, p]) => p!.name)); // ['Widget', 'Gadget'];
|
|
222
|
+
* @example
|
|
223
|
+
* // Building a sorted index
|
|
224
|
+
* type Product = { id: number; name: string; price: number };
|
|
225
|
+
* const products: Product[] = [
|
|
226
|
+
* { id: 1, name: 'Widget', price: 25 },
|
|
227
|
+
* { id: 2, name: 'Gadget', price: 50 },
|
|
228
|
+
* { id: 3, name: 'Doohickey', price: 15 }
|
|
229
|
+
* ];
|
|
230
|
+
*
|
|
231
|
+
* const index = new SkipList<number, Product, Product>(products, {
|
|
232
|
+
* toEntryFn: (p: Product) => [p.price, p]
|
|
233
|
+
* });
|
|
234
|
+
*
|
|
235
|
+
* // Iterate in sorted order by price
|
|
236
|
+
* const names = [...index.values()].map(p => p!.name);
|
|
237
|
+
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
238
|
+
*
|
|
239
|
+
* // Range search: products between $20 and $60
|
|
240
|
+
* const range = index.rangeSearch([20, 60]);
|
|
241
|
+
* console.log(range.map(([, p]) => p!.name)); // ['Widget', 'Gadget'];
|
|
456
242
|
*/
|
|
457
243
|
override get(key: K): V | undefined {
|
|
458
244
|
const node = this._findNode(key);
|
|
@@ -462,53 +248,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
462
248
|
/**
|
|
463
249
|
* Check if a key exists.
|
|
464
250
|
* Overrides base O(n) with O(log n) skip-list search.
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
* @example
|
|
508
|
-
* // Check key existence
|
|
509
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [3, 'c'], [5, 'e']]);
|
|
510
|
-
* console.log(sl.has(3)); // true;
|
|
511
|
-
* console.log(sl.has(4)); // false;
|
|
251
|
+
* @example
|
|
252
|
+
* // Check key existence
|
|
253
|
+
* const sl = new SkipList<number, string>([
|
|
254
|
+
* [1, 'a'],
|
|
255
|
+
* [3, 'c'],
|
|
256
|
+
* [5, 'e']
|
|
257
|
+
* ]);
|
|
258
|
+
* console.log(sl.has(3)); // true;
|
|
259
|
+
* console.log(sl.has(4)); // false;
|
|
512
260
|
*/
|
|
513
261
|
override has(key: K): boolean {
|
|
514
262
|
return this._findNode(key) !== undefined;
|
|
@@ -516,77 +264,31 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
516
264
|
|
|
517
265
|
/**
|
|
518
266
|
* Delete a key. Returns `true` if the key was found and removed.
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
* @example
|
|
562
|
-
* // Fast lookup with deletion
|
|
563
|
-
* const cache = new SkipList<string, number>();
|
|
564
|
-
*
|
|
565
|
-
* cache.set('alpha', 1);
|
|
566
|
-
* cache.set('beta', 2);
|
|
567
|
-
* cache.set('gamma', 3);
|
|
568
|
-
*
|
|
569
|
-
* console.log(cache.has('beta')); // true;
|
|
570
|
-
* cache.delete('beta');
|
|
571
|
-
* console.log(cache.has('beta')); // false;
|
|
572
|
-
* console.log(cache.size); // 2;
|
|
267
|
+
* @example
|
|
268
|
+
* // Fast lookup with deletion
|
|
269
|
+
* const cache = new SkipList<string, number>();
|
|
270
|
+
*
|
|
271
|
+
* cache.set('alpha', 1);
|
|
272
|
+
* cache.set('beta', 2);
|
|
273
|
+
* cache.set('gamma', 3);
|
|
274
|
+
*
|
|
275
|
+
* console.log(cache.has('beta')); // true;
|
|
276
|
+
* cache.delete('beta');
|
|
277
|
+
* console.log(cache.has('beta')); // false;
|
|
278
|
+
* console.log(cache.size); // 2;
|
|
573
279
|
*/
|
|
574
280
|
delete(key: K): boolean {
|
|
575
281
|
const cmp = this.#comparator;
|
|
576
282
|
const update = this._findUpdate(key);
|
|
577
|
-
|
|
578
283
|
const target = update[0].forward[0];
|
|
579
284
|
if (!target || cmp(target.key, key) !== 0) return false;
|
|
580
|
-
|
|
581
285
|
for (let i = 0; i < this._level; i++) {
|
|
582
286
|
if (update[i].forward[i] !== target) break;
|
|
583
287
|
update[i].forward[i] = target.forward[i];
|
|
584
288
|
}
|
|
585
|
-
|
|
586
289
|
while (this._level > 0 && !this._head.forward[this._level - 1]) {
|
|
587
290
|
this._level--;
|
|
588
291
|
}
|
|
589
|
-
|
|
590
292
|
this._size--;
|
|
591
293
|
return true;
|
|
592
294
|
}
|
|
@@ -595,52 +297,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
595
297
|
|
|
596
298
|
/**
|
|
597
299
|
* Returns the first (smallest key) entry, or `undefined` if empty.
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
* @example
|
|
641
|
-
* // Access the minimum entry
|
|
642
|
-
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
643
|
-
* console.log(sl.first()); // [1, 'a'];
|
|
300
|
+
* @example
|
|
301
|
+
* // Access the minimum entry
|
|
302
|
+
* const sl = new SkipList<number, string>([
|
|
303
|
+
* [5, 'e'],
|
|
304
|
+
* [1, 'a'],
|
|
305
|
+
* [3, 'c']
|
|
306
|
+
* ]);
|
|
307
|
+
* console.log(sl.first()); // [1, 'a'];
|
|
644
308
|
*/
|
|
645
309
|
first(): [K, V | undefined] | undefined {
|
|
646
310
|
const node = this._head.forward[0];
|
|
@@ -649,52 +313,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
649
313
|
|
|
650
314
|
/**
|
|
651
315
|
* Returns the last (largest key) entry, or `undefined` if empty.
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
* @example
|
|
695
|
-
* // Access the maximum entry
|
|
696
|
-
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
697
|
-
* console.log(sl.last()); // [5, 'e'];
|
|
316
|
+
* @example
|
|
317
|
+
* // Access the maximum entry
|
|
318
|
+
* const sl = new SkipList<number, string>([
|
|
319
|
+
* [5, 'e'],
|
|
320
|
+
* [1, 'a'],
|
|
321
|
+
* [3, 'c']
|
|
322
|
+
* ]);
|
|
323
|
+
* console.log(sl.last()); // [5, 'e'];
|
|
698
324
|
*/
|
|
699
325
|
last(): [K, V | undefined] | undefined {
|
|
700
326
|
let current = this._head;
|
|
@@ -708,50 +334,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
708
334
|
|
|
709
335
|
/**
|
|
710
336
|
* Remove and return the first (smallest key) entry.
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
* @example
|
|
751
|
-
* // Remove and return smallest
|
|
752
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
753
|
-
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
754
|
-
* console.log(sl.size); // 2;
|
|
337
|
+
* @example
|
|
338
|
+
* // Remove and return smallest
|
|
339
|
+
* const sl = new SkipList<number, string>([
|
|
340
|
+
* [1, 'a'],
|
|
341
|
+
* [2, 'b'],
|
|
342
|
+
* [3, 'c']
|
|
343
|
+
* ]);
|
|
344
|
+
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
345
|
+
* console.log(sl.size); // 2;
|
|
755
346
|
*/
|
|
756
347
|
pollFirst(): [K, V | undefined] | undefined {
|
|
757
348
|
const entry = this.first();
|
|
@@ -762,50 +353,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
762
353
|
|
|
763
354
|
/**
|
|
764
355
|
* Remove and return the last (largest key) entry.
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
* @example
|
|
805
|
-
* // Remove and return largest
|
|
806
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
807
|
-
* console.log(sl.pollLast()); // [3, 'c'];
|
|
808
|
-
* console.log(sl.size); // 2;
|
|
356
|
+
* @example
|
|
357
|
+
* // Remove and return largest
|
|
358
|
+
* const sl = new SkipList<number, string>([
|
|
359
|
+
* [1, 'a'],
|
|
360
|
+
* [2, 'b'],
|
|
361
|
+
* [3, 'c']
|
|
362
|
+
* ]);
|
|
363
|
+
* console.log(sl.pollLast()); // [3, 'c'];
|
|
364
|
+
* console.log(sl.size); // 2;
|
|
809
365
|
*/
|
|
810
366
|
pollLast(): [K, V | undefined] | undefined {
|
|
811
367
|
const entry = this.last();
|
|
@@ -816,53 +372,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
816
372
|
|
|
817
373
|
/**
|
|
818
374
|
* Least entry ≥ key, or `undefined`.
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
* @example
|
|
862
|
-
* // Least entry ≥ key
|
|
863
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
864
|
-
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
865
|
-
* console.log(sl.ceiling(20)); // [20, 'b'];
|
|
375
|
+
* @example
|
|
376
|
+
* // Least entry ≥ key
|
|
377
|
+
* const sl = new SkipList<number, string>([
|
|
378
|
+
* [10, 'a'],
|
|
379
|
+
* [20, 'b'],
|
|
380
|
+
* [30, 'c']
|
|
381
|
+
* ]);
|
|
382
|
+
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
383
|
+
* console.log(sl.ceiling(20)); // [20, 'b'];
|
|
866
384
|
*/
|
|
867
385
|
ceiling(key: K): [K, V | undefined] | undefined {
|
|
868
386
|
const cmp = this.#comparator;
|
|
@@ -878,53 +396,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
878
396
|
|
|
879
397
|
/**
|
|
880
398
|
* Greatest entry ≤ key, or `undefined`.
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
* @example
|
|
924
|
-
* // Greatest entry ≤ key
|
|
925
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
926
|
-
* console.log(sl.floor(25)); // [20, 'b'];
|
|
927
|
-
* console.log(sl.floor(5)); // undefined;
|
|
399
|
+
* @example
|
|
400
|
+
* // Greatest entry ≤ key
|
|
401
|
+
* const sl = new SkipList<number, string>([
|
|
402
|
+
* [10, 'a'],
|
|
403
|
+
* [20, 'b'],
|
|
404
|
+
* [30, 'c']
|
|
405
|
+
* ]);
|
|
406
|
+
* console.log(sl.floor(25)); // [20, 'b'];
|
|
407
|
+
* console.log(sl.floor(5)); // undefined;
|
|
928
408
|
*/
|
|
929
409
|
floor(key: K): [K, V | undefined] | undefined {
|
|
930
410
|
const cmp = this.#comparator;
|
|
@@ -935,7 +415,6 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
935
415
|
}
|
|
936
416
|
}
|
|
937
417
|
const result = current === this._head ? undefined : current;
|
|
938
|
-
|
|
939
418
|
// Check if we're exactly at or before key
|
|
940
419
|
if (result && cmp(result.key, key) <= 0) return [result.key, result.value];
|
|
941
420
|
return undefined;
|
|
@@ -943,50 +422,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
943
422
|
|
|
944
423
|
/**
|
|
945
424
|
* Least entry strictly > key, or `undefined`.
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
* @example
|
|
986
|
-
* // Strictly greater entry
|
|
987
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
988
|
-
* console.log(sl.higher(15)); // [20, 'b'];
|
|
989
|
-
* console.log(sl.higher(30)); // undefined;
|
|
425
|
+
* @example
|
|
426
|
+
* // Strictly greater entry
|
|
427
|
+
* const sl = new SkipList<number, string>([
|
|
428
|
+
* [10, 'a'],
|
|
429
|
+
* [20, 'b'],
|
|
430
|
+
* [30, 'c']
|
|
431
|
+
* ]);
|
|
432
|
+
* console.log(sl.higher(15)); // [20, 'b'];
|
|
433
|
+
* console.log(sl.higher(30)); // undefined;
|
|
990
434
|
*/
|
|
991
435
|
higher(key: K): [K, V | undefined] | undefined {
|
|
992
436
|
const cmp = this.#comparator;
|
|
@@ -1002,50 +446,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1002
446
|
|
|
1003
447
|
/**
|
|
1004
448
|
* Greatest entry strictly < key, or `undefined`.
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
* @example
|
|
1045
|
-
* // Strictly less entry
|
|
1046
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
1047
|
-
* console.log(sl.lower(25)); // [20, 'b'];
|
|
1048
|
-
* console.log(sl.lower(10)); // undefined;
|
|
449
|
+
* @example
|
|
450
|
+
* // Strictly less entry
|
|
451
|
+
* const sl = new SkipList<number, string>([
|
|
452
|
+
* [10, 'a'],
|
|
453
|
+
* [20, 'b'],
|
|
454
|
+
* [30, 'c']
|
|
455
|
+
* ]);
|
|
456
|
+
* console.log(sl.lower(25)); // [20, 'b'];
|
|
457
|
+
* console.log(sl.lower(10)); // undefined;
|
|
1049
458
|
*/
|
|
1050
459
|
lower(key: K): [K, V | undefined] | undefined {
|
|
1051
460
|
const cmp = this.#comparator;
|
|
@@ -1064,60 +473,27 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1064
473
|
|
|
1065
474
|
/**
|
|
1066
475
|
* Returns entries within the given key range.
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
* @example
|
|
1110
|
-
* // Find entries in a range
|
|
1111
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]);
|
|
1112
|
-
* const result = sl.rangeSearch([2, 4]);
|
|
1113
|
-
* console.log(result); // [[2, 'b'], [3, 'c'], [4, 'd']];
|
|
476
|
+
* @example
|
|
477
|
+
* // Find entries in a range
|
|
478
|
+
* const sl = new SkipList<number, string>([
|
|
479
|
+
* [1, 'a'],
|
|
480
|
+
* [2, 'b'],
|
|
481
|
+
* [3, 'c'],
|
|
482
|
+
* [4, 'd'],
|
|
483
|
+
* [5, 'e']
|
|
484
|
+
* ]);
|
|
485
|
+
* const result = sl.rangeSearch([2, 4]);
|
|
486
|
+
* console.log(result); // [
|
|
487
|
+
* // [2, 'b'],
|
|
488
|
+
* // [3, 'c'],
|
|
489
|
+
* // [4, 'd']
|
|
490
|
+
* // ];
|
|
1114
491
|
*/
|
|
1115
492
|
rangeSearch(range: [K, K], options: SkipListRangeOptions = {}): Array<[K, V | undefined]> {
|
|
1116
493
|
const { lowInclusive = true, highInclusive = true } = options;
|
|
1117
494
|
const [low, high] = range;
|
|
1118
495
|
const cmp = this.#comparator;
|
|
1119
496
|
const out: Array<[K, V | undefined]> = [];
|
|
1120
|
-
|
|
1121
497
|
// Start from the first node >= low
|
|
1122
498
|
let current = this._head;
|
|
1123
499
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
@@ -1126,20 +502,16 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1126
502
|
}
|
|
1127
503
|
}
|
|
1128
504
|
current = current.forward[0]!;
|
|
1129
|
-
|
|
1130
505
|
while (current) {
|
|
1131
506
|
const cmpHigh = cmp(current.key, high);
|
|
1132
507
|
if (cmpHigh > 0) break;
|
|
1133
508
|
if (cmpHigh === 0 && !highInclusive) break;
|
|
1134
|
-
|
|
1135
509
|
const cmpLow = cmp(current.key, low);
|
|
1136
510
|
if (cmpLow > 0 || (cmpLow === 0 && lowInclusive)) {
|
|
1137
511
|
out.push([current.key, current.value]);
|
|
1138
512
|
}
|
|
1139
|
-
|
|
1140
513
|
current = current.forward[0]!;
|
|
1141
514
|
}
|
|
1142
|
-
|
|
1143
515
|
return out;
|
|
1144
516
|
}
|
|
1145
517
|
|
|
@@ -1147,50 +519,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1147
519
|
|
|
1148
520
|
/**
|
|
1149
521
|
* Creates a new SkipList with entries transformed by callback.
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
* @example
|
|
1190
|
-
* // Transform entries
|
|
1191
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
1192
|
-
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
1193
|
-
* console.log([...mapped.values()]); // ['A', 'B'];
|
|
522
|
+
* @example
|
|
523
|
+
* // Transform entries
|
|
524
|
+
* const sl = new SkipList<number, string>([
|
|
525
|
+
* [1, 'a'],
|
|
526
|
+
* [2, 'b']
|
|
527
|
+
* ]);
|
|
528
|
+
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
529
|
+
* console.log([...mapped.values()]); // ['A', 'B'];
|
|
1194
530
|
*/
|
|
1195
531
|
map<MK, MV>(
|
|
1196
532
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
@@ -1207,55 +543,17 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1207
543
|
|
|
1208
544
|
/**
|
|
1209
545
|
* Creates a new SkipList with entries that pass the predicate.
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
* @example
|
|
1250
|
-
* // Filter entries
|
|
1251
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
1252
|
-
* const result = sl.filter((v, k) => k > 1);
|
|
1253
|
-
* console.log(result.size); // 2;
|
|
546
|
+
* @example
|
|
547
|
+
* // Filter entries
|
|
548
|
+
* const sl = new SkipList<number, string>([
|
|
549
|
+
* [1, 'a'],
|
|
550
|
+
* [2, 'b'],
|
|
551
|
+
* [3, 'c']
|
|
552
|
+
* ]);
|
|
553
|
+
* const result = sl.filter((v, k) => k > 1);
|
|
554
|
+
* console.log(result.size); // 2;
|
|
1254
555
|
*/
|
|
1255
|
-
filter(
|
|
1256
|
-
callbackfn: EntryCallback<K, V | undefined, boolean>,
|
|
1257
|
-
thisArg?: unknown
|
|
1258
|
-
): this {
|
|
556
|
+
filter(callbackfn: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
|
|
1259
557
|
const out = new SkipList<K, V, R>([], {
|
|
1260
558
|
comparator: this.#isDefaultComparator ? undefined : this.#comparator,
|
|
1261
559
|
maxLevel: this._maxLevel,
|
|
@@ -1270,7 +568,6 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1270
568
|
}
|
|
1271
569
|
|
|
1272
570
|
// ─── Iterator (required by IterableEntryBase) ────────────────
|
|
1273
|
-
|
|
1274
571
|
protected _getIterator(): IterableIterator<[K, V | undefined]> {
|
|
1275
572
|
const head = this._head;
|
|
1276
573
|
return (function* () {
|
|
@@ -1291,14 +588,12 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1291
588
|
const cmp = this.#comparator;
|
|
1292
589
|
const update: SkipListNode<K, V>[] = new Array(this._maxLevel).fill(this._head);
|
|
1293
590
|
let current = this._head;
|
|
1294
|
-
|
|
1295
591
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
1296
592
|
while (current.forward[i] && cmp(current.forward[i]!.key, key) < 0) {
|
|
1297
593
|
current = current.forward[i]!;
|
|
1298
594
|
}
|
|
1299
595
|
update[i] = current;
|
|
1300
596
|
}
|
|
1301
|
-
|
|
1302
597
|
return update;
|
|
1303
598
|
}
|
|
1304
599
|
|
|
@@ -1308,13 +603,11 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1308
603
|
protected _findNode(key: K): SkipListNode<K, V> | undefined {
|
|
1309
604
|
const cmp = this.#comparator;
|
|
1310
605
|
let current = this._head;
|
|
1311
|
-
|
|
1312
606
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
1313
607
|
while (current.forward[i] && cmp(current.forward[i]!.key, key) < 0) {
|
|
1314
608
|
current = current.forward[i]!;
|
|
1315
609
|
}
|
|
1316
610
|
}
|
|
1317
|
-
|
|
1318
611
|
const candidate = current.forward[0];
|
|
1319
612
|
if (candidate && cmp(candidate.key, key) === 0) return candidate;
|
|
1320
613
|
return undefined;
|