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.
Files changed (28) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +13 -13
  3. package/benchmark/report.html +13 -13
  4. package/benchmark/report.json +168 -144
  5. package/dist/cjs/data-structures/binary-tree/binary-tree.js +19 -19
  6. package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
  7. package/dist/cjs/data-structures/binary-tree/rb-tree.d.ts +158 -135
  8. package/dist/cjs/data-structures/binary-tree/rb-tree.js +415 -386
  9. package/dist/cjs/data-structures/binary-tree/rb-tree.js.map +1 -1
  10. package/dist/cjs/data-structures/binary-tree/tree-multi-map.d.ts +1 -0
  11. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +84 -76
  12. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
  13. package/dist/mjs/data-structures/binary-tree/binary-tree.js +19 -19
  14. package/dist/mjs/data-structures/binary-tree/rb-tree.d.ts +158 -135
  15. package/dist/mjs/data-structures/binary-tree/rb-tree.js +412 -386
  16. package/dist/mjs/data-structures/binary-tree/tree-multi-map.d.ts +1 -0
  17. package/dist/mjs/data-structures/binary-tree/tree-multi-map.js +84 -76
  18. package/dist/umd/data-structure-typed.js +477 -431
  19. package/dist/umd/data-structure-typed.min.js +2 -2
  20. package/dist/umd/data-structure-typed.min.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/data-structures/binary-tree/binary-tree.ts +19 -19
  23. package/src/data-structures/binary-tree/rb-tree.ts +437 -395
  24. package/src/data-structures/binary-tree/tree-multi-map.ts +85 -82
  25. package/test/performance/data-structures/binary-tree/rb-tree.test.ts +26 -16
  26. package/test/unit/data-structures/binary-tree/overall.test.ts +23 -21
  27. package/test/unit/data-structures/binary-tree/rb-tree.test.ts +168 -105
  28. 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
- if (newNode === undefined) return false;
198
+ const orgCount = newNode?.count || 0;
199
+ const isSuccessAdded = super.add(newNode);
196
200
 
197
- const orgNodeCount = newNode?.count || 0;
198
- const inserted = super.add(newNode);
199
- if (inserted) {
200
- this._count += orgNodeCount;
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
- const deleteResults: BinaryTreeDeleteResult<NODE>[] = [];
236
- if (identifier === null) return deleteResults;
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
- // Move to the right or left based on the comparison with the identifier
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
- // If the target node is not found, decrement size and return
260
- if (targetNode === this._Sentinel) {
261
- return;
262
- }
244
+ if (!nodeToDelete) {
245
+ return results;
246
+ }
263
247
 
264
- if (ignoreCount || targetNode.count <= 1) {
265
- // Store the parent of the target node and its original color
266
- let parentNode = targetNode;
267
- let parentNodeOriginalColor: number = parentNode.color;
268
-
269
- // Handle deletion based on the number of children of the target node
270
- if (targetNode.left === this._Sentinel) {
271
- // Target node has no left child - deletion case 1
272
- currentNode = targetNode.right;
273
- this._rbTransplant(targetNode, targetNode.right!);
274
- } else if (targetNode.right === this._Sentinel) {
275
- // Target node has no right child - deletion case 2
276
- currentNode = targetNode.left;
277
- this._rbTransplant(targetNode, targetNode.left!);
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
- // Target node has both left and right children - deletion case 3
280
- parentNode = this.getLeftMost(targetNode.right)!;
281
- parentNodeOriginalColor = parentNode.color;
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
- // Replace parentNode with its right child and update connections
289
- this._rbTransplant(parentNode, parentNode.right!);
290
- parentNode.right = targetNode.right;
291
- parentNode.right!.parent = parentNode;
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
- // Fix the Red-Black Tree properties after deletion
302
- if (parentNodeOriginalColor === RBTNColor.BLACK) {
303
- this._fixDelete(currentNode!);
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
- // Decrement the size and store information about the deleted node
307
- this._size--;
308
- this._count -= targetNode.count;
309
- deleteResults.push({ deleted: targetNode, needBalanced: undefined });
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
- // Call the helper function with the root of the tree
317
- deleteHelper(this.root);
321
+ results.push({ deleted: nodeToDelete, needBalanced: undefined });
318
322
 
319
- // Return the result array
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 arr = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND, true);
10
+ const randomArray = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND - 1, true);
11
11
  const cOrderedMap = new OrderedMap<number, number>();
12
12
 
13
- suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => {
14
- rbTree.clear();
15
- for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]);
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 < arr.length; i++) cOrderedMap.setElement(arr[i], arr[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
- .add(`${HUNDRED_THOUSAND.toLocaleString()} add & delete randomly`, () => {
26
- rbTree.clear();
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 < arr.length; i++) rbTree.add(arr[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(6);
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(NaN);
166
- expect(tmm.getNodeByKey(7)?.left?.key).toBe(NaN);
167
- expect(tmm.getHeight()).toBe(5);
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(6);
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(NaN);
178
- expect(tmm.getNodeByKey(6)?.left?.key).toBe(1);
179
- expect(tmm.getHeight()).toBe(5);
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([6, 1, 9, 3, 2, 5, 4]);
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(6);
187
+ expect(clonedTMM.root?.key).toBe(3);
187
188
  expect(clonedTMM.root?.left?.key).toBe(1);
188
- expect(clonedTMM.root?.right?.key).toBe(9);
189
- expect(clonedTMM.root?.right?.left?.key).toBe(NaN);
190
- expect(clonedTMM.getNodeByKey(6)?.left?.key).toBe(1);
191
- expect(clonedTMM.getHeight()).toBe(5);
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([6, 1, 9, 3, 2, 5, 4]);
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(4);
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(5);
223
- expect(rbTree.root?.right?.left?.key).toBe(4);
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(4);
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(4);
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]);