data-structure-typed 2.5.3 → 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/.husky/pre-commit +3 -0
- package/CHANGELOG.md +1 -1
- package/MIGRATION.md +48 -0
- package/README.md +20 -2
- package/README_CN.md +20 -2
- package/SPECIFICATION.md +24 -0
- package/SPECIFICATION.zh-CN.md +24 -0
- package/dist/cjs/binary-tree.cjs +1897 -19
- package/dist/cjs/graph.cjs +174 -0
- package/dist/cjs/hash.cjs +33 -0
- package/dist/cjs/heap.cjs +71 -0
- package/dist/cjs/index.cjs +2383 -3
- package/dist/cjs/linked-list.cjs +224 -2
- package/dist/cjs/matrix.cjs +24 -0
- package/dist/cjs/priority-queue.cjs +71 -0
- package/dist/cjs/queue.cjs +221 -1
- package/dist/cjs/stack.cjs +59 -0
- package/dist/cjs/trie.cjs +62 -0
- package/dist/cjs-legacy/binary-tree.cjs +1897 -19
- package/dist/cjs-legacy/graph.cjs +174 -0
- package/dist/cjs-legacy/hash.cjs +33 -0
- package/dist/cjs-legacy/heap.cjs +71 -0
- package/dist/cjs-legacy/index.cjs +2383 -3
- package/dist/cjs-legacy/linked-list.cjs +224 -2
- package/dist/cjs-legacy/matrix.cjs +24 -0
- package/dist/cjs-legacy/priority-queue.cjs +71 -0
- package/dist/cjs-legacy/queue.cjs +221 -1
- package/dist/cjs-legacy/stack.cjs +59 -0
- package/dist/cjs-legacy/trie.cjs +62 -0
- package/dist/esm/binary-tree.mjs +1897 -19
- package/dist/esm/graph.mjs +174 -0
- package/dist/esm/hash.mjs +33 -0
- package/dist/esm/heap.mjs +71 -0
- package/dist/esm/index.mjs +2383 -3
- package/dist/esm/linked-list.mjs +224 -2
- package/dist/esm/matrix.mjs +24 -0
- package/dist/esm/priority-queue.mjs +71 -0
- package/dist/esm/queue.mjs +221 -1
- package/dist/esm/stack.mjs +59 -0
- package/dist/esm/trie.mjs +62 -0
- package/dist/esm-legacy/binary-tree.mjs +1897 -19
- package/dist/esm-legacy/graph.mjs +174 -0
- package/dist/esm-legacy/hash.mjs +33 -0
- package/dist/esm-legacy/heap.mjs +71 -0
- package/dist/esm-legacy/index.mjs +2383 -3
- package/dist/esm-legacy/linked-list.mjs +224 -2
- package/dist/esm-legacy/matrix.mjs +24 -0
- package/dist/esm-legacy/priority-queue.mjs +71 -0
- package/dist/esm-legacy/queue.mjs +221 -1
- package/dist/esm-legacy/stack.mjs +59 -0
- package/dist/esm-legacy/trie.mjs +62 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +17 -0
- package/dist/types/data-structures/base/linear-base.d.ts +6 -0
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +36 -0
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +42 -0
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +75 -0
- package/dist/types/data-structures/binary-tree/bst.d.ts +72 -0
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +57 -0
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +18 -0
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +375 -0
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +389 -0
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +330 -0
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +438 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +30 -0
- package/dist/types/data-structures/graph/undirected-graph.d.ts +27 -0
- package/dist/types/data-structures/hash/hash-map.d.ts +33 -0
- package/dist/types/data-structures/heap/heap.d.ts +42 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +75 -2
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +45 -0
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +54 -0
- package/dist/types/data-structures/matrix/matrix.d.ts +24 -0
- package/dist/types/data-structures/queue/deque.d.ts +90 -1
- package/dist/types/data-structures/queue/queue.d.ts +36 -0
- package/dist/types/data-structures/stack/stack.d.ts +30 -0
- package/dist/types/data-structures/trie/trie.d.ts +36 -0
- package/dist/umd/data-structure-typed.js +2383 -3
- package/dist/umd/data-structure-typed.min.js +3 -3
- 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 +30 -26
- 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/jest.integration.config.js +1 -2
- package/package.json +51 -50
- package/src/common/error.ts +15 -32
- package/src/common/index.ts +0 -3
- package/src/data-structures/base/iterable-element-base.ts +32 -3
- package/src/data-structures/base/linear-base.ts +13 -36
- package/src/data-structures/binary-tree/avl-tree.ts +31 -493
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +47 -530
- package/src/data-structures/binary-tree/binary-tree.ts +326 -1236
- package/src/data-structures/binary-tree/bst.ts +158 -1010
- package/src/data-structures/binary-tree/red-black-tree.ts +451 -1233
- package/src/data-structures/binary-tree/segment-tree.ts +73 -333
- package/src/data-structures/binary-tree/tree-map.ts +462 -4749
- package/src/data-structures/binary-tree/tree-multi-map.ts +310 -4530
- package/src/data-structures/binary-tree/tree-multi-set.ts +300 -3652
- package/src/data-structures/binary-tree/tree-set.ts +437 -4443
- package/src/data-structures/graph/abstract-graph.ts +98 -167
- package/src/data-structures/graph/directed-graph.ts +137 -532
- package/src/data-structures/graph/map-graph.ts +0 -3
- package/src/data-structures/graph/undirected-graph.ts +132 -484
- package/src/data-structures/hash/hash-map.ts +154 -549
- package/src/data-structures/heap/heap.ts +200 -753
- package/src/data-structures/linked-list/doubly-linked-list.ts +153 -809
- package/src/data-structures/linked-list/singly-linked-list.ts +122 -749
- package/src/data-structures/linked-list/skip-linked-list.ts +211 -864
- package/src/data-structures/matrix/matrix.ts +179 -494
- 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 +241 -807
- package/src/data-structures/queue/queue.ts +102 -589
- package/src/data-structures/stack/stack.ts +76 -475
- package/src/data-structures/trie/trie.ts +98 -592
- 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,126 +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
|
-
* @example
|
|
177
|
-
* // Check if empty
|
|
178
|
-
* const sl = new SkipList<number, string>();
|
|
179
|
-
* console.log(sl.isEmpty()); // true;
|
|
126
|
+
* @example
|
|
127
|
+
* // Check if empty
|
|
128
|
+
* const sl = new SkipList<number, string>();
|
|
129
|
+
* console.log(sl.isEmpty()); // true;
|
|
180
130
|
*/
|
|
181
131
|
isEmpty(): boolean {
|
|
182
132
|
return this._size === 0;
|
|
183
133
|
}
|
|
184
134
|
|
|
185
|
-
|
|
135
|
+
/**
|
|
186
136
|
* Remove all entries
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
* @example
|
|
224
|
-
* // Remove all entries
|
|
225
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
226
|
-
* sl.clear();
|
|
227
|
-
* 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;
|
|
228
145
|
*/
|
|
229
146
|
clear(): void {
|
|
230
147
|
this._head = new SkipListNode<K, V>(undefined as K, undefined as V, this._maxLevel);
|
|
@@ -232,50 +149,17 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
232
149
|
this._size = 0;
|
|
233
150
|
}
|
|
234
151
|
|
|
235
|
-
|
|
152
|
+
/**
|
|
236
153
|
* Create independent copy
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
* @example
|
|
274
|
-
* // Create independent copy
|
|
275
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
276
|
-
* const copy = sl.clone();
|
|
277
|
-
* copy.delete(1);
|
|
278
|
-
* 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;
|
|
279
163
|
*/
|
|
280
164
|
clone(): this {
|
|
281
165
|
return new SkipList<K, V, R>(this as Iterable<[K, V | undefined]>, {
|
|
@@ -290,88 +174,44 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
290
174
|
/**
|
|
291
175
|
* Insert or update a key-value pair. Returns `this` for chaining.
|
|
292
176
|
* Unique keys only — if key exists, value is updated in place.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
* @example
|
|
333
|
-
* // In-memory sorted key-value store
|
|
334
|
-
* const store = new SkipList<number, string>();
|
|
335
|
-
*
|
|
336
|
-
* store.set(3, 'three');
|
|
337
|
-
* store.set(1, 'one');
|
|
338
|
-
* store.set(5, 'five');
|
|
339
|
-
* store.set(2, 'two');
|
|
340
|
-
*
|
|
341
|
-
* console.log(store.get(3)); // 'three';
|
|
342
|
-
* console.log(store.get(1)); // 'one';
|
|
343
|
-
* console.log(store.get(5)); // 'five';
|
|
344
|
-
*
|
|
345
|
-
* // Update existing key
|
|
346
|
-
* store.set(3, 'THREE');
|
|
347
|
-
* 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';
|
|
348
193
|
*/
|
|
349
194
|
set(key: K, value: V): this {
|
|
350
195
|
const cmp = this.#comparator;
|
|
351
196
|
const update = this._findUpdate(key);
|
|
352
|
-
|
|
353
197
|
// If key already exists, update value in place
|
|
354
198
|
const existing = update[0].forward[0];
|
|
355
199
|
if (existing && cmp(existing.key, key) === 0) {
|
|
356
200
|
existing.value = value;
|
|
357
201
|
return this;
|
|
358
202
|
}
|
|
359
|
-
|
|
360
203
|
const newLevel = this._randomLevel();
|
|
361
204
|
const newNode = new SkipListNode(key, value, newLevel);
|
|
362
|
-
|
|
363
205
|
if (newLevel > this._level) {
|
|
364
206
|
for (let i = this._level; i < newLevel; i++) {
|
|
365
207
|
update[i] = this._head;
|
|
366
208
|
}
|
|
367
209
|
this._level = newLevel;
|
|
368
210
|
}
|
|
369
|
-
|
|
370
211
|
for (let i = 0; i < newLevel; i++) {
|
|
371
212
|
newNode.forward[i] = update[i].forward[i];
|
|
372
213
|
update[i].forward[i] = newNode;
|
|
373
214
|
}
|
|
374
|
-
|
|
375
215
|
this._size++;
|
|
376
216
|
return this;
|
|
377
217
|
}
|
|
@@ -379,65 +219,26 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
379
219
|
/**
|
|
380
220
|
* Get the value for a key, or `undefined` if not found.
|
|
381
221
|
* Overrides base O(n) with O(log n) skip-list search.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
* @example
|
|
422
|
-
* // Building a sorted index
|
|
423
|
-
* type Product = { id: number; name: string; price: number };
|
|
424
|
-
* const products: Product[] = [
|
|
425
|
-
* { id: 1, name: 'Widget', price: 25 },
|
|
426
|
-
* { id: 2, name: 'Gadget', price: 50 },
|
|
427
|
-
* { id: 3, name: 'Doohickey', price: 15 }
|
|
428
|
-
* ];
|
|
429
|
-
*
|
|
430
|
-
* const index = new SkipList<number, Product, Product>(products, {
|
|
431
|
-
* toEntryFn: (p: Product) => [p.price, p]
|
|
432
|
-
* });
|
|
433
|
-
*
|
|
434
|
-
* // Iterate in sorted order by price
|
|
435
|
-
* const names = [...index.values()].map(p => p!.name);
|
|
436
|
-
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
437
|
-
*
|
|
438
|
-
* // Range search: products between $20 and $60
|
|
439
|
-
* const range = index.rangeSearch([20, 60]);
|
|
440
|
-
* 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'];
|
|
441
242
|
*/
|
|
442
243
|
override get(key: K): V | undefined {
|
|
443
244
|
const node = this._findNode(key);
|
|
@@ -447,50 +248,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
447
248
|
/**
|
|
448
249
|
* Check if a key exists.
|
|
449
250
|
* Overrides base O(n) with O(log n) skip-list search.
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
* @example
|
|
490
|
-
* // Check key existence
|
|
491
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [3, 'c'], [5, 'e']]);
|
|
492
|
-
* console.log(sl.has(3)); // true;
|
|
493
|
-
* 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;
|
|
494
260
|
*/
|
|
495
261
|
override has(key: K): boolean {
|
|
496
262
|
return this._findNode(key) !== undefined;
|
|
@@ -498,74 +264,31 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
498
264
|
|
|
499
265
|
/**
|
|
500
266
|
* Delete a key. Returns `true` if the key was found and removed.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
* @example
|
|
541
|
-
* // Fast lookup with deletion
|
|
542
|
-
* const cache = new SkipList<string, number>();
|
|
543
|
-
*
|
|
544
|
-
* cache.set('alpha', 1);
|
|
545
|
-
* cache.set('beta', 2);
|
|
546
|
-
* cache.set('gamma', 3);
|
|
547
|
-
*
|
|
548
|
-
* console.log(cache.has('beta')); // true;
|
|
549
|
-
* cache.delete('beta');
|
|
550
|
-
* console.log(cache.has('beta')); // false;
|
|
551
|
-
* 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;
|
|
552
279
|
*/
|
|
553
280
|
delete(key: K): boolean {
|
|
554
281
|
const cmp = this.#comparator;
|
|
555
282
|
const update = this._findUpdate(key);
|
|
556
|
-
|
|
557
283
|
const target = update[0].forward[0];
|
|
558
284
|
if (!target || cmp(target.key, key) !== 0) return false;
|
|
559
|
-
|
|
560
285
|
for (let i = 0; i < this._level; i++) {
|
|
561
286
|
if (update[i].forward[i] !== target) break;
|
|
562
287
|
update[i].forward[i] = target.forward[i];
|
|
563
288
|
}
|
|
564
|
-
|
|
565
289
|
while (this._level > 0 && !this._head.forward[this._level - 1]) {
|
|
566
290
|
this._level--;
|
|
567
291
|
}
|
|
568
|
-
|
|
569
292
|
this._size--;
|
|
570
293
|
return true;
|
|
571
294
|
}
|
|
@@ -574,49 +297,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
574
297
|
|
|
575
298
|
/**
|
|
576
299
|
* Returns the first (smallest key) entry, or `undefined` if empty.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
* @example
|
|
617
|
-
* // Access the minimum entry
|
|
618
|
-
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
619
|
-
* 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'];
|
|
620
308
|
*/
|
|
621
309
|
first(): [K, V | undefined] | undefined {
|
|
622
310
|
const node = this._head.forward[0];
|
|
@@ -625,49 +313,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
625
313
|
|
|
626
314
|
/**
|
|
627
315
|
* Returns the last (largest key) entry, or `undefined` if empty.
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
* @example
|
|
668
|
-
* // Access the maximum entry
|
|
669
|
-
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
670
|
-
* 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'];
|
|
671
324
|
*/
|
|
672
325
|
last(): [K, V | undefined] | undefined {
|
|
673
326
|
let current = this._head;
|
|
@@ -681,47 +334,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
681
334
|
|
|
682
335
|
/**
|
|
683
336
|
* Remove and return the first (smallest key) entry.
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
* @example
|
|
721
|
-
* // Remove and return smallest
|
|
722
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
723
|
-
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
724
|
-
* 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;
|
|
725
346
|
*/
|
|
726
347
|
pollFirst(): [K, V | undefined] | undefined {
|
|
727
348
|
const entry = this.first();
|
|
@@ -732,47 +353,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
732
353
|
|
|
733
354
|
/**
|
|
734
355
|
* Remove and return the last (largest key) entry.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
* @example
|
|
772
|
-
* // Remove and return largest
|
|
773
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
774
|
-
* console.log(sl.pollLast()); // [3, 'c'];
|
|
775
|
-
* 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;
|
|
776
365
|
*/
|
|
777
366
|
pollLast(): [K, V | undefined] | undefined {
|
|
778
367
|
const entry = this.last();
|
|
@@ -783,50 +372,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
783
372
|
|
|
784
373
|
/**
|
|
785
374
|
* Least entry ≥ key, or `undefined`.
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
* @example
|
|
826
|
-
* // Least entry ≥ key
|
|
827
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
828
|
-
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
829
|
-
* 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'];
|
|
830
384
|
*/
|
|
831
385
|
ceiling(key: K): [K, V | undefined] | undefined {
|
|
832
386
|
const cmp = this.#comparator;
|
|
@@ -842,50 +396,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
842
396
|
|
|
843
397
|
/**
|
|
844
398
|
* Greatest entry ≤ key, or `undefined`.
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
* @example
|
|
885
|
-
* // Greatest entry ≤ key
|
|
886
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
887
|
-
* console.log(sl.floor(25)); // [20, 'b'];
|
|
888
|
-
* 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;
|
|
889
408
|
*/
|
|
890
409
|
floor(key: K): [K, V | undefined] | undefined {
|
|
891
410
|
const cmp = this.#comparator;
|
|
@@ -896,7 +415,6 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
896
415
|
}
|
|
897
416
|
}
|
|
898
417
|
const result = current === this._head ? undefined : current;
|
|
899
|
-
|
|
900
418
|
// Check if we're exactly at or before key
|
|
901
419
|
if (result && cmp(result.key, key) <= 0) return [result.key, result.value];
|
|
902
420
|
return undefined;
|
|
@@ -904,47 +422,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
904
422
|
|
|
905
423
|
/**
|
|
906
424
|
* Least entry strictly > key, or `undefined`.
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
* @example
|
|
944
|
-
* // Strictly greater entry
|
|
945
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
946
|
-
* console.log(sl.higher(15)); // [20, 'b'];
|
|
947
|
-
* 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;
|
|
948
434
|
*/
|
|
949
435
|
higher(key: K): [K, V | undefined] | undefined {
|
|
950
436
|
const cmp = this.#comparator;
|
|
@@ -960,47 +446,15 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
960
446
|
|
|
961
447
|
/**
|
|
962
448
|
* Greatest entry strictly < key, or `undefined`.
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
* @example
|
|
1000
|
-
* // Strictly less entry
|
|
1001
|
-
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
1002
|
-
* console.log(sl.lower(25)); // [20, 'b'];
|
|
1003
|
-
* 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;
|
|
1004
458
|
*/
|
|
1005
459
|
lower(key: K): [K, V | undefined] | undefined {
|
|
1006
460
|
const cmp = this.#comparator;
|
|
@@ -1019,57 +473,27 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1019
473
|
|
|
1020
474
|
/**
|
|
1021
475
|
* Returns entries within the given key range.
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
* @example
|
|
1062
|
-
* // Find entries in a range
|
|
1063
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]);
|
|
1064
|
-
* const result = sl.rangeSearch([2, 4]);
|
|
1065
|
-
* 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
|
+
* // ];
|
|
1066
491
|
*/
|
|
1067
492
|
rangeSearch(range: [K, K], options: SkipListRangeOptions = {}): Array<[K, V | undefined]> {
|
|
1068
493
|
const { lowInclusive = true, highInclusive = true } = options;
|
|
1069
494
|
const [low, high] = range;
|
|
1070
495
|
const cmp = this.#comparator;
|
|
1071
496
|
const out: Array<[K, V | undefined]> = [];
|
|
1072
|
-
|
|
1073
497
|
// Start from the first node >= low
|
|
1074
498
|
let current = this._head;
|
|
1075
499
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
@@ -1078,20 +502,16 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1078
502
|
}
|
|
1079
503
|
}
|
|
1080
504
|
current = current.forward[0]!;
|
|
1081
|
-
|
|
1082
505
|
while (current) {
|
|
1083
506
|
const cmpHigh = cmp(current.key, high);
|
|
1084
507
|
if (cmpHigh > 0) break;
|
|
1085
508
|
if (cmpHigh === 0 && !highInclusive) break;
|
|
1086
|
-
|
|
1087
509
|
const cmpLow = cmp(current.key, low);
|
|
1088
510
|
if (cmpLow > 0 || (cmpLow === 0 && lowInclusive)) {
|
|
1089
511
|
out.push([current.key, current.value]);
|
|
1090
512
|
}
|
|
1091
|
-
|
|
1092
513
|
current = current.forward[0]!;
|
|
1093
514
|
}
|
|
1094
|
-
|
|
1095
515
|
return out;
|
|
1096
516
|
}
|
|
1097
517
|
|
|
@@ -1099,47 +519,14 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1099
519
|
|
|
1100
520
|
/**
|
|
1101
521
|
* Creates a new SkipList with entries transformed by callback.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
* @example
|
|
1139
|
-
* // Transform entries
|
|
1140
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
1141
|
-
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
1142
|
-
* 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'];
|
|
1143
530
|
*/
|
|
1144
531
|
map<MK, MV>(
|
|
1145
532
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
@@ -1156,52 +543,17 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1156
543
|
|
|
1157
544
|
/**
|
|
1158
545
|
* Creates a new SkipList with entries that pass the predicate.
|
|
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
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
* @example
|
|
1196
|
-
* // Filter entries
|
|
1197
|
-
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
1198
|
-
* const result = sl.filter((v, k) => k > 1);
|
|
1199
|
-
* 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;
|
|
1200
555
|
*/
|
|
1201
|
-
filter(
|
|
1202
|
-
callbackfn: EntryCallback<K, V | undefined, boolean>,
|
|
1203
|
-
thisArg?: unknown
|
|
1204
|
-
): this {
|
|
556
|
+
filter(callbackfn: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
|
|
1205
557
|
const out = new SkipList<K, V, R>([], {
|
|
1206
558
|
comparator: this.#isDefaultComparator ? undefined : this.#comparator,
|
|
1207
559
|
maxLevel: this._maxLevel,
|
|
@@ -1216,7 +568,6 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1216
568
|
}
|
|
1217
569
|
|
|
1218
570
|
// ─── Iterator (required by IterableEntryBase) ────────────────
|
|
1219
|
-
|
|
1220
571
|
protected _getIterator(): IterableIterator<[K, V | undefined]> {
|
|
1221
572
|
const head = this._head;
|
|
1222
573
|
return (function* () {
|
|
@@ -1237,14 +588,12 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1237
588
|
const cmp = this.#comparator;
|
|
1238
589
|
const update: SkipListNode<K, V>[] = new Array(this._maxLevel).fill(this._head);
|
|
1239
590
|
let current = this._head;
|
|
1240
|
-
|
|
1241
591
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
1242
592
|
while (current.forward[i] && cmp(current.forward[i]!.key, key) < 0) {
|
|
1243
593
|
current = current.forward[i]!;
|
|
1244
594
|
}
|
|
1245
595
|
update[i] = current;
|
|
1246
596
|
}
|
|
1247
|
-
|
|
1248
597
|
return update;
|
|
1249
598
|
}
|
|
1250
599
|
|
|
@@ -1254,13 +603,11 @@ export class SkipList<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
|
|
|
1254
603
|
protected _findNode(key: K): SkipListNode<K, V> | undefined {
|
|
1255
604
|
const cmp = this.#comparator;
|
|
1256
605
|
let current = this._head;
|
|
1257
|
-
|
|
1258
606
|
for (let i = this._level - 1; i >= 0; i--) {
|
|
1259
607
|
while (current.forward[i] && cmp(current.forward[i]!.key, key) < 0) {
|
|
1260
608
|
current = current.forward[i]!;
|
|
1261
609
|
}
|
|
1262
610
|
}
|
|
1263
|
-
|
|
1264
611
|
const candidate = current.forward[0];
|
|
1265
612
|
if (candidate && cmp(candidate.key, key) === 0) return candidate;
|
|
1266
613
|
return undefined;
|