data-structure-typed 1.50.5 → 1.50.6
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 +1 -1
- package/README.md +13 -13
- package/benchmark/report.html +13 -13
- package/benchmark/report.json +168 -144
- package/dist/cjs/data-structures/binary-tree/binary-tree.js +19 -19
- package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/rb-tree.d.ts +158 -135
- package/dist/cjs/data-structures/binary-tree/rb-tree.js +415 -386
- package/dist/cjs/data-structures/binary-tree/rb-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.d.ts +1 -0
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +84 -76
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/binary-tree.js +19 -19
- package/dist/mjs/data-structures/binary-tree/rb-tree.d.ts +158 -135
- package/dist/mjs/data-structures/binary-tree/rb-tree.js +412 -386
- package/dist/mjs/data-structures/binary-tree/tree-multi-map.d.ts +1 -0
- package/dist/mjs/data-structures/binary-tree/tree-multi-map.js +84 -76
- package/dist/umd/data-structure-typed.js +477 -431
- package/dist/umd/data-structure-typed.min.js +2 -2
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +1 -1
- package/src/data-structures/binary-tree/binary-tree.ts +19 -19
- package/src/data-structures/binary-tree/rb-tree.ts +437 -395
- package/src/data-structures/binary-tree/tree-multi-map.ts +85 -82
- package/test/performance/data-structures/binary-tree/rb-tree.test.ts +26 -16
- package/test/unit/data-structures/binary-tree/overall.test.ts +23 -21
- package/test/unit/data-structures/binary-tree/rb-tree.test.ts +168 -105
- package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +311 -192
|
@@ -88,10 +88,13 @@ export class TreeMultiMap<
|
|
|
88
88
|
* @returns the sum of the count property of all nodes in the tree.
|
|
89
89
|
*/
|
|
90
90
|
get count(): number {
|
|
91
|
+
return this._count;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getMutableCount(): number {
|
|
91
95
|
let sum = 0;
|
|
92
96
|
this.dfs(node => (sum += node.count));
|
|
93
97
|
return sum;
|
|
94
|
-
// return this._count;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
/**
|
|
@@ -192,14 +195,15 @@ export class TreeMultiMap<
|
|
|
192
195
|
*/
|
|
193
196
|
override add(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V, count = 1): boolean {
|
|
194
197
|
const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value, count);
|
|
195
|
-
|
|
198
|
+
const orgCount = newNode?.count || 0;
|
|
199
|
+
const isSuccessAdded = super.add(newNode);
|
|
196
200
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
if (isSuccessAdded) {
|
|
202
|
+
this._count += orgCount;
|
|
203
|
+
return true;
|
|
204
|
+
} else {
|
|
205
|
+
return false;
|
|
201
206
|
}
|
|
202
|
-
return true;
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
/**
|
|
@@ -232,92 +236,91 @@ export class TreeMultiMap<
|
|
|
232
236
|
callback: C = this._defaultOneParamCallback as C,
|
|
233
237
|
ignoreCount = false
|
|
234
238
|
): BinaryTreeDeleteResult<NODE>[] {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// Helper function to perform deletion
|
|
239
|
-
const deleteHelper = (node: NODE | undefined): void => {
|
|
240
|
-
// Initialize targetNode to the sentinel node
|
|
241
|
-
let targetNode: NODE = this._Sentinel;
|
|
242
|
-
let currentNode: NODE | undefined;
|
|
243
|
-
|
|
244
|
-
// Find the node to be deleted based on the identifier
|
|
245
|
-
while (node !== this._Sentinel) {
|
|
246
|
-
// Update targetNode if the current node matches the identifier
|
|
247
|
-
if (node && callback(node) === identifier) {
|
|
248
|
-
targetNode = node;
|
|
249
|
-
}
|
|
239
|
+
if (identifier === null) return [];
|
|
240
|
+
const results: BinaryTreeDeleteResult<NODE>[] = [];
|
|
250
241
|
|
|
251
|
-
|
|
252
|
-
if (node && identifier && callback(node) <= identifier) {
|
|
253
|
-
node = node.right;
|
|
254
|
-
} else {
|
|
255
|
-
node = node?.left;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
242
|
+
const nodeToDelete = this.isRealNode(identifier) ? identifier : this.getNode(identifier, callback);
|
|
258
243
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
244
|
+
if (!nodeToDelete) {
|
|
245
|
+
return results;
|
|
246
|
+
}
|
|
263
247
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
248
|
+
let originalColor = nodeToDelete.color;
|
|
249
|
+
let replacementNode: NODE | undefined;
|
|
250
|
+
|
|
251
|
+
if (!this.isRealNode(nodeToDelete.left)) {
|
|
252
|
+
replacementNode = nodeToDelete.right;
|
|
253
|
+
if (ignoreCount || nodeToDelete.count <= 1) {
|
|
254
|
+
this._transplant(nodeToDelete, nodeToDelete.right);
|
|
255
|
+
this._count -= nodeToDelete.count;
|
|
256
|
+
} else {
|
|
257
|
+
nodeToDelete.count--;
|
|
258
|
+
this._count--;
|
|
259
|
+
results.push({ deleted: nodeToDelete, needBalanced: undefined });
|
|
260
|
+
return results;
|
|
261
|
+
}
|
|
262
|
+
} else if (!this.isRealNode(nodeToDelete.right)) {
|
|
263
|
+
replacementNode = nodeToDelete.left;
|
|
264
|
+
if (ignoreCount || nodeToDelete.count <= 1) {
|
|
265
|
+
this._transplant(nodeToDelete, nodeToDelete.left);
|
|
266
|
+
this._count -= nodeToDelete.count;
|
|
267
|
+
} else {
|
|
268
|
+
nodeToDelete.count--;
|
|
269
|
+
this._count--;
|
|
270
|
+
results.push({ deleted: nodeToDelete, needBalanced: undefined });
|
|
271
|
+
return results;
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
const successor = this.getLeftMost(nodeToDelete.right);
|
|
275
|
+
if (successor) {
|
|
276
|
+
originalColor = successor.color;
|
|
277
|
+
replacementNode = successor.right;
|
|
278
|
+
|
|
279
|
+
if (successor.parent === nodeToDelete) {
|
|
280
|
+
if (this.isRealNode(replacementNode)) {
|
|
281
|
+
replacementNode.parent = successor;
|
|
282
|
+
}
|
|
278
283
|
} else {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
currentNode = parentNode.right;
|
|
283
|
-
|
|
284
|
-
if (parentNode.parent === targetNode) {
|
|
285
|
-
// Target node's right child becomes its parent's left child
|
|
286
|
-
currentNode!.parent = parentNode;
|
|
284
|
+
if (ignoreCount || nodeToDelete.count <= 1) {
|
|
285
|
+
this._transplant(successor, successor.right);
|
|
286
|
+
this._count -= nodeToDelete.count;
|
|
287
287
|
} else {
|
|
288
|
-
|
|
289
|
-
this.
|
|
290
|
-
|
|
291
|
-
|
|
288
|
+
nodeToDelete.count--;
|
|
289
|
+
this._count--;
|
|
290
|
+
results.push({ deleted: nodeToDelete, needBalanced: undefined });
|
|
291
|
+
return results;
|
|
292
|
+
}
|
|
293
|
+
successor.right = nodeToDelete.right;
|
|
294
|
+
if (this.isRealNode(successor.right)) {
|
|
295
|
+
successor.right.parent = successor;
|
|
292
296
|
}
|
|
293
|
-
|
|
294
|
-
// Replace the target node with its in-order successor
|
|
295
|
-
this._rbTransplant(targetNode, parentNode);
|
|
296
|
-
parentNode.left = targetNode.left;
|
|
297
|
-
parentNode.left!.parent = parentNode;
|
|
298
|
-
parentNode.color = targetNode.color;
|
|
299
297
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
298
|
+
if (ignoreCount || nodeToDelete.count <= 1) {
|
|
299
|
+
this._transplant(nodeToDelete, successor);
|
|
300
|
+
this._count -= nodeToDelete.count;
|
|
301
|
+
} else {
|
|
302
|
+
nodeToDelete.count--;
|
|
303
|
+
this._count--;
|
|
304
|
+
results.push({ deleted: nodeToDelete, needBalanced: undefined });
|
|
305
|
+
return results;
|
|
304
306
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
} else {
|
|
311
|
-
targetNode.count--;
|
|
312
|
-
this._count--;
|
|
307
|
+
successor.left = nodeToDelete.left;
|
|
308
|
+
if (this.isRealNode(successor.left)) {
|
|
309
|
+
successor.left.parent = successor;
|
|
310
|
+
}
|
|
311
|
+
successor.color = nodeToDelete.color;
|
|
313
312
|
}
|
|
314
|
-
}
|
|
313
|
+
}
|
|
314
|
+
this._size--;
|
|
315
|
+
|
|
316
|
+
// If the original color was black, fix the tree
|
|
317
|
+
if (originalColor === RBTNColor.BLACK) {
|
|
318
|
+
this._deleteFixup(replacementNode);
|
|
319
|
+
}
|
|
315
320
|
|
|
316
|
-
|
|
317
|
-
deleteHelper(this.root);
|
|
321
|
+
results.push({ deleted: nodeToDelete, needBalanced: undefined });
|
|
318
322
|
|
|
319
|
-
|
|
320
|
-
return deleteResults;
|
|
323
|
+
return results;
|
|
321
324
|
}
|
|
322
325
|
|
|
323
326
|
/**
|
|
@@ -7,33 +7,43 @@ import { isCompetitor } from '../../../config';
|
|
|
7
7
|
const suite = new Benchmark.Suite();
|
|
8
8
|
const rbTree = new RedBlackTree();
|
|
9
9
|
const { HUNDRED_THOUSAND } = magnitude;
|
|
10
|
-
const
|
|
10
|
+
const randomArray = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND - 1, true);
|
|
11
11
|
const cOrderedMap = new OrderedMap<number, number>();
|
|
12
12
|
|
|
13
|
-
suite
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
})
|
|
13
|
+
suite
|
|
14
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} add orderly`, () => {
|
|
15
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.add(i);
|
|
16
|
+
})
|
|
17
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} delete orderly`, () => {
|
|
18
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.delete(i);
|
|
19
|
+
})
|
|
20
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} add randomly`, () => {
|
|
21
|
+
rbTree.clear();
|
|
22
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.add(randomArray[i]);
|
|
23
|
+
})
|
|
24
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} delete randomly`, () => {
|
|
25
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.delete(randomArray[i]);
|
|
26
|
+
})
|
|
27
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} add orderly`, () => {
|
|
28
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.add(i);
|
|
29
|
+
})
|
|
30
|
+
.add(`${HUNDRED_THOUSAND.toLocaleString()} delete randomly`, () => {
|
|
31
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.delete(randomArray[i]);
|
|
32
|
+
});
|
|
17
33
|
|
|
18
34
|
if (isCompetitor) {
|
|
19
35
|
suite.add(`CPT ${HUNDRED_THOUSAND.toLocaleString()} add`, () => {
|
|
20
|
-
for (let i = 0; i <
|
|
36
|
+
for (let i = 0; i < randomArray.length; i++) cOrderedMap.setElement(randomArray[i], randomArray[i]);
|
|
21
37
|
});
|
|
22
38
|
}
|
|
23
39
|
|
|
24
|
-
suite
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]);
|
|
28
|
-
for (let i = 0; i < arr.length; i++) rbTree.delete(arr[i]);
|
|
29
|
-
})
|
|
30
|
-
.add(`${HUNDRED_THOUSAND.toLocaleString()} getNode`, () => {
|
|
31
|
-
for (let i = 0; i < arr.length; i++) rbTree.getNode(arr[i]);
|
|
32
|
-
});
|
|
40
|
+
suite.add(`${HUNDRED_THOUSAND.toLocaleString()} getNode randomly`, () => {
|
|
41
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.getNode(randomArray[i]);
|
|
42
|
+
});
|
|
33
43
|
|
|
34
44
|
suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & iterator`, () => {
|
|
35
45
|
rbTree.clear();
|
|
36
|
-
for (let i = 0; i <
|
|
46
|
+
for (let i = 0; i < randomArray.length; i++) rbTree.add(randomArray[i]);
|
|
37
47
|
const entries = [...rbTree];
|
|
38
48
|
return entries.length === HUNDRED_THOUSAND;
|
|
39
49
|
});
|
|
@@ -158,40 +158,41 @@ describe('Overall BinaryTree Test', () => {
|
|
|
158
158
|
tmm.add(5);
|
|
159
159
|
tmm.add(4);
|
|
160
160
|
expect(tmm.count).toBe(10);
|
|
161
|
-
expect(tmm.root?.key).toBe(
|
|
161
|
+
expect(tmm.root?.key).toBe(3);
|
|
162
162
|
expect(tmm.root?.left?.key).toBe(1);
|
|
163
163
|
expect(tmm.root?.left?.left?.key).toBe(NaN);
|
|
164
164
|
expect(tmm.root?.right?.key).toBe(7);
|
|
165
|
-
expect(tmm.root?.right?.left?.key).toBe(
|
|
166
|
-
expect(tmm.getNodeByKey(7)?.left?.key).toBe(
|
|
167
|
-
expect(tmm.getHeight()).toBe(
|
|
165
|
+
expect(tmm.root?.right?.left?.key).toBe(5);
|
|
166
|
+
expect(tmm.getNodeByKey(7)?.left?.key).toBe(5);
|
|
167
|
+
expect(tmm.getHeight()).toBe(3);
|
|
168
168
|
expect(tmm.has(9)).toBe(true);
|
|
169
169
|
expect(tmm.has(7)).toBe(true);
|
|
170
170
|
expect(tmm.delete(7)[0].deleted?.key).toBe(7);
|
|
171
171
|
expect(tmm.has(7)).toBe(false);
|
|
172
172
|
expect(tmm.size).toBe(7);
|
|
173
173
|
expect(tmm.count).toBe(9);
|
|
174
|
-
expect(tmm.root?.key).toBe(
|
|
174
|
+
expect(tmm.root?.key).toBe(3);
|
|
175
175
|
expect(tmm.root?.left?.key).toBe(1);
|
|
176
176
|
expect(tmm.root?.right?.key).toBe(9);
|
|
177
|
-
expect(tmm.root?.right?.left?.key).toBe(
|
|
178
|
-
expect(tmm.getNodeByKey(6)?.left?.key).toBe(
|
|
179
|
-
expect(tmm.getHeight()).toBe(
|
|
177
|
+
expect(tmm.root?.right?.left?.key).toBe(5);
|
|
178
|
+
expect(tmm.getNodeByKey(6)?.left?.key).toBe(NaN);
|
|
179
|
+
expect(tmm.getHeight()).toBe(3);
|
|
180
180
|
expect(tmm.has(9)).toBe(true);
|
|
181
181
|
expect(tmm.has(7)).toBe(false);
|
|
182
|
-
expect(tmm.bfs()).toEqual([
|
|
182
|
+
expect(tmm.bfs()).toEqual([3, 1, 9, 2, 5, 4, 6]);
|
|
183
|
+
// expect(tmm.bfs()).toEqual([6, 1, 9, 3, 2, 5, 4]);
|
|
183
184
|
const clonedTMM = tmm.clone();
|
|
184
185
|
expect(clonedTMM.size).toBe(7);
|
|
185
186
|
expect(clonedTMM.count).toBe(9);
|
|
186
|
-
expect(clonedTMM.root?.key).toBe(
|
|
187
|
+
expect(clonedTMM.root?.key).toBe(3);
|
|
187
188
|
expect(clonedTMM.root?.left?.key).toBe(1);
|
|
188
|
-
expect(clonedTMM.root?.right?.key).toBe(
|
|
189
|
-
expect(clonedTMM.root?.right?.left?.key).toBe(
|
|
190
|
-
expect(clonedTMM.getNodeByKey(6)?.left?.key).toBe(
|
|
191
|
-
expect(clonedTMM.getHeight()).toBe(
|
|
189
|
+
expect(clonedTMM.root?.right?.key).toBe(5);
|
|
190
|
+
expect(clonedTMM.root?.right?.left?.key).toBe(4);
|
|
191
|
+
expect(clonedTMM.getNodeByKey(6)?.left?.key).toBe(NaN);
|
|
192
|
+
expect(clonedTMM.getHeight()).toBe(3);
|
|
192
193
|
expect(clonedTMM.has(9)).toBe(true);
|
|
193
194
|
expect(clonedTMM.has(7)).toBe(false);
|
|
194
|
-
expect(clonedTMM.bfs()).toEqual([
|
|
195
|
+
expect(clonedTMM.bfs()).toEqual([3, 1, 5, 2, 4, 9, 6]);
|
|
195
196
|
});
|
|
196
197
|
|
|
197
198
|
it('Should clone a RedBlackTree works fine', () => {
|
|
@@ -211,7 +212,7 @@ describe('Overall BinaryTree Test', () => {
|
|
|
211
212
|
expect(rbTree.root?.right?.key).toBe(7);
|
|
212
213
|
expect(rbTree.root?.right?.left?.key).toBe(5);
|
|
213
214
|
expect(rbTree.getNodeByKey(7)?.left?.key).toBe(5);
|
|
214
|
-
expect(rbTree.getHeight()).toBe(
|
|
215
|
+
expect(rbTree.getHeight()).toBe(3);
|
|
215
216
|
expect(rbTree.has(9)).toBe(true);
|
|
216
217
|
expect(rbTree.has(7)).toBe(true);
|
|
217
218
|
expect(rbTree.delete(7)?.[0]?.deleted?.key).toBe(7);
|
|
@@ -219,13 +220,14 @@ describe('Overall BinaryTree Test', () => {
|
|
|
219
220
|
expect(rbTree.size).toBe(7);
|
|
220
221
|
expect(rbTree.root?.key).toBe(3);
|
|
221
222
|
expect(rbTree.root?.left?.key).toBe(1);
|
|
222
|
-
expect(rbTree.root?.right?.key).toBe(
|
|
223
|
-
expect(rbTree.root?.right?.left?.key).toBe(
|
|
223
|
+
expect(rbTree.root?.right?.key).toBe(9);
|
|
224
|
+
expect(rbTree.root?.right?.left?.key).toBe(5);
|
|
224
225
|
expect(rbTree.getNodeByKey(6)?.left?.key).toBe(NaN);
|
|
225
|
-
expect(rbTree.getHeight()).toBe(
|
|
226
|
+
expect(rbTree.getHeight()).toBe(3);
|
|
226
227
|
expect(rbTree.has(9)).toBe(true);
|
|
227
228
|
expect(rbTree.has(7)).toBe(false);
|
|
228
|
-
expect(rbTree.bfs()).toEqual([3, 1, 5, 2, 4, 9, 6]);
|
|
229
|
+
// expect(rbTree.bfs()).toEqual([3, 1, 5, 2, 4, 9, 6]);
|
|
230
|
+
expect(rbTree.bfs()).toEqual([3, 1, 9, 2, 5, 4, 6]);
|
|
229
231
|
const clonedRbTree = rbTree.clone();
|
|
230
232
|
expect(clonedRbTree.size).toBe(7);
|
|
231
233
|
expect(clonedRbTree.root?.key).toBe(3);
|
|
@@ -233,7 +235,7 @@ describe('Overall BinaryTree Test', () => {
|
|
|
233
235
|
expect(clonedRbTree.root?.right?.key).toBe(5);
|
|
234
236
|
expect(clonedRbTree.root?.right?.left?.key).toBe(4);
|
|
235
237
|
expect(clonedRbTree.getNodeByKey(6)?.left?.key).toBe(NaN);
|
|
236
|
-
expect(clonedRbTree.getHeight()).toBe(
|
|
238
|
+
expect(clonedRbTree.getHeight()).toBe(3);
|
|
237
239
|
expect(clonedRbTree.has(9)).toBe(true);
|
|
238
240
|
expect(clonedRbTree.has(7)).toBe(false);
|
|
239
241
|
expect(clonedRbTree.bfs()).toEqual([3, 1, 5, 2, 4, 9, 6]);
|