binary-tree-typed 2.4.5 → 2.5.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.
Files changed (94) hide show
  1. package/README.md +0 -84
  2. package/dist/cjs/index.cjs +1476 -404
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs-legacy/index.cjs +1473 -401
  5. package/dist/cjs-legacy/index.cjs.map +1 -1
  6. package/dist/esm/index.mjs +1476 -404
  7. package/dist/esm/index.mjs.map +1 -1
  8. package/dist/esm-legacy/index.mjs +1473 -401
  9. package/dist/esm-legacy/index.mjs.map +1 -1
  10. package/dist/types/data-structures/base/index.d.ts +1 -0
  11. package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
  12. package/dist/types/data-structures/base/iterable-entry-base.d.ts +8 -8
  13. package/dist/types/data-structures/base/linear-base.d.ts +3 -3
  14. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +380 -51
  15. package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +487 -147
  16. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +956 -80
  17. package/dist/types/data-structures/binary-tree/bst.d.ts +816 -29
  18. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +610 -31
  19. package/dist/types/data-structures/binary-tree/segment-tree.d.ts +326 -135
  20. package/dist/types/data-structures/binary-tree/tree-map.d.ts +3781 -6
  21. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +3607 -201
  22. package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +2874 -65
  23. package/dist/types/data-structures/binary-tree/tree-set.d.ts +3528 -6
  24. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -4
  25. package/dist/types/data-structures/graph/directed-graph.d.ts +429 -47
  26. package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
  27. package/dist/types/data-structures/graph/undirected-graph.d.ts +393 -59
  28. package/dist/types/data-structures/hash/hash-map.d.ts +473 -89
  29. package/dist/types/data-structures/heap/heap.d.ts +581 -99
  30. package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
  31. package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
  32. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +646 -47
  33. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +596 -68
  34. package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +793 -12
  35. package/dist/types/data-structures/matrix/matrix.d.ts +499 -0
  36. package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
  37. package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
  38. package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
  39. package/dist/types/data-structures/queue/deque.d.ts +593 -71
  40. package/dist/types/data-structures/queue/queue.d.ts +463 -42
  41. package/dist/types/data-structures/stack/stack.d.ts +384 -32
  42. package/dist/types/data-structures/trie/trie.d.ts +470 -48
  43. package/dist/types/interfaces/graph.d.ts +1 -1
  44. package/dist/types/types/common.d.ts +2 -2
  45. package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
  46. package/dist/types/types/data-structures/heap/heap.d.ts +1 -0
  47. package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
  48. package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -0
  49. package/dist/types/types/utils/validate-type.d.ts +4 -4
  50. package/dist/umd/binary-tree-typed.js +1469 -397
  51. package/dist/umd/binary-tree-typed.js.map +1 -1
  52. package/dist/umd/binary-tree-typed.min.js +5 -5
  53. package/dist/umd/binary-tree-typed.min.js.map +1 -1
  54. package/package.json +2 -2
  55. package/src/data-structures/base/index.ts +1 -0
  56. package/src/data-structures/base/iterable-element-base.ts +4 -5
  57. package/src/data-structures/base/iterable-entry-base.ts +8 -8
  58. package/src/data-structures/base/linear-base.ts +3 -3
  59. package/src/data-structures/binary-tree/avl-tree.ts +386 -51
  60. package/src/data-structures/binary-tree/binary-indexed-tree.ts +596 -247
  61. package/src/data-structures/binary-tree/binary-tree.ts +956 -81
  62. package/src/data-structures/binary-tree/bst.ts +840 -35
  63. package/src/data-structures/binary-tree/red-black-tree.ts +689 -97
  64. package/src/data-structures/binary-tree/segment-tree.ts +498 -249
  65. package/src/data-structures/binary-tree/tree-map.ts +3784 -7
  66. package/src/data-structures/binary-tree/tree-multi-map.ts +3614 -211
  67. package/src/data-structures/binary-tree/tree-multi-set.ts +2874 -65
  68. package/src/data-structures/binary-tree/tree-set.ts +3531 -10
  69. package/src/data-structures/graph/abstract-graph.ts +4 -4
  70. package/src/data-structures/graph/directed-graph.ts +429 -47
  71. package/src/data-structures/graph/map-graph.ts +59 -1
  72. package/src/data-structures/graph/undirected-graph.ts +393 -59
  73. package/src/data-structures/hash/hash-map.ts +476 -92
  74. package/src/data-structures/heap/heap.ts +581 -99
  75. package/src/data-structures/heap/max-heap.ts +46 -0
  76. package/src/data-structures/heap/min-heap.ts +59 -0
  77. package/src/data-structures/linked-list/doubly-linked-list.ts +646 -47
  78. package/src/data-structures/linked-list/singly-linked-list.ts +596 -68
  79. package/src/data-structures/linked-list/skip-linked-list.ts +1067 -90
  80. package/src/data-structures/matrix/matrix.ts +584 -12
  81. package/src/data-structures/priority-queue/max-priority-queue.ts +57 -0
  82. package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
  83. package/src/data-structures/priority-queue/priority-queue.ts +60 -0
  84. package/src/data-structures/queue/deque.ts +592 -70
  85. package/src/data-structures/queue/queue.ts +463 -42
  86. package/src/data-structures/stack/stack.ts +384 -32
  87. package/src/data-structures/trie/trie.ts +470 -48
  88. package/src/interfaces/graph.ts +1 -1
  89. package/src/types/common.ts +2 -2
  90. package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
  91. package/src/types/data-structures/heap/heap.ts +1 -0
  92. package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
  93. package/src/types/data-structures/priority-queue/priority-queue.ts +1 -0
  94. package/src/types/utils/validate-type.ts +4 -4
@@ -98,16 +98,12 @@ export class RedBlackTreeNode<K = any, V = any> {
98
98
  *
99
99
  * @returns The height.
100
100
  */
101
+ /* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
101
102
  get height(): number {
102
103
  return this._height;
103
104
  }
104
105
 
105
- /**
106
- * Sets the height of the node.
107
- * @remarks Time O(1), Space O(1)
108
- *
109
- * @param value - The new height.
110
- */
106
+ /* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
111
107
  set height(value: number) {
112
108
  this._height = value;
113
109
  }
@@ -142,20 +138,11 @@ export class RedBlackTreeNode<K = any, V = any> {
142
138
  *
143
139
  * @returns The subtree node count.
144
140
  */
141
+ /* istanbul ignore next -- internal field, exercised indirectly via tree operations */
145
142
  get count(): number {
146
143
  return this._count;
147
144
  }
148
145
 
149
- /**
150
- * Sets the count of nodes in the subtree.
151
- * @remarks Time O(1), Space O(1)
152
- *
153
- * @param value - The new count.
154
- */
155
- set count(value: number) {
156
- this._count = value;
157
- }
158
-
159
146
  /**
160
147
  * Gets the position of the node relative to its parent.
161
148
  * @remarks Time O(1), Space O(1)
@@ -173,6 +160,7 @@ export class RedBlackTreeNode<K = any, V = any> {
173
160
  return this.left || this.right ? 'ROOT_RIGHT' : 'RIGHT';
174
161
  }
175
162
 
163
+ /* istanbul ignore next -- defensive: unreachable if tree structure is correct */
176
164
  return 'MAL_NODE';
177
165
  }
178
166
  }
@@ -187,23 +175,6 @@ export class RedBlackTreeNode<K = any, V = any> {
187
175
  * 2. It is BST itself. Compared with Heap which is not completely ordered, RedBlackTree is completely ordered.
188
176
  *
189
177
  * @example
190
- * // basic Red-Black Tree with simple number keys
191
- * // Create a simple Red-Black Tree with numeric keys
192
- * const tree = new RedBlackTree([5, 2, 8, 1, 9]);
193
- *
194
- * tree.print();
195
- * // _2___
196
- * // / \
197
- * // 1 _8_
198
- * // / \
199
- * // 5 9
200
- *
201
- * // Verify the tree maintains sorted order
202
- * console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
203
- *
204
- * // Check size
205
- * console.log(tree.size); // 5;
206
- * @example
207
178
  * // Red-Black Tree with key-value pairs for lookups
208
179
  * interface Employee {
209
180
  * id: number;
@@ -369,6 +340,130 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
369
340
  /**
370
341
  * Remove all nodes and clear internal caches.
371
342
  * @remarks Time O(n) average, Space O(1)
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+
377
+
378
+
379
+
380
+
381
+
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
+
422
+
423
+
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+
450
+
451
+
452
+
453
+
454
+
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+ * @example
463
+ * // Remove all entries
464
+ * const rbt = new RedBlackTree<number>([1, 2, 3]);
465
+ * rbt.clear();
466
+ * console.log(rbt.isEmpty()); // true;
372
467
  */
373
468
  override clear() {
374
469
  super.clear();
@@ -604,10 +699,10 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
604
699
  if (hMin === NIL || hMax === NIL) {
605
700
  this._setMinCache(newNode);
606
701
  this._setMaxCache(newNode);
607
- } else if (parent === hMax && lastCompared > 0) {
608
- this._setMaxCache(newNode);
609
- } else if (parent === hMin && lastCompared < 0) {
610
- this._setMinCache(newNode);
702
+ } else /* istanbul ignore next -- boundary fast-paths at top of _setKVNode intercept boundary inserts before normal path */ if (parent === hMax && lastCompared > 0) {
703
+ /* istanbul ignore next */ this._setMaxCache(newNode);
704
+ } else /* istanbul ignore next */ if (parent === hMin && lastCompared < 0) {
705
+ /* istanbul ignore next */ this._setMinCache(newNode);
611
706
  } else {
612
707
  if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
613
708
  if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
@@ -701,6 +796,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
701
796
  return newNode;
702
797
  }
703
798
 
799
+ /* istanbul ignore next -- structurally unreachable: predecessor never has a right child (it's the max of left subtree) */
704
800
  return this._setKVNode(key, value)?.node;
705
801
  }
706
802
 
@@ -741,6 +837,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
741
837
  return newNode;
742
838
  }
743
839
 
840
+ /* istanbul ignore next -- structurally unreachable: successor never has a left child (it's the min of right subtree) */
744
841
  return this._setKVNode(key, value)?.node;
745
842
  }
746
843
 
@@ -760,6 +857,143 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
760
857
  * - updates via a single-pass search (no double walk)
761
858
  *
762
859
  * @remarks Time O(log n) average, Space O(1)
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
+
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
+
924
+
925
+
926
+
927
+
928
+
929
+
930
+
931
+
932
+
933
+
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+
943
+
944
+
945
+
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
+ * @example
981
+ * // basic Red-Black Tree with simple number keys
982
+ * // Create a simple Red-Black Tree with numeric keys
983
+ * const tree = new RedBlackTree([5, 2, 8, 1, 9]);
984
+ *
985
+ * tree.print();
986
+ * // _2___
987
+ * // / \
988
+ * // 1 _8_
989
+ * // / \
990
+ * // 5 9
991
+ *
992
+ * // Verify the tree maintains sorted order
993
+ * console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
994
+ *
995
+ * // Check size
996
+ * console.log(tree.size); // 5;
763
997
  */
764
998
  override set(
765
999
  keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
@@ -812,6 +1046,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
812
1046
  }
813
1047
  return true;
814
1048
  }
1049
+ /* istanbul ignore next -- defensive: _insert only returns CREATED|UPDATED */
815
1050
  return false;
816
1051
  }
817
1052
 
@@ -820,6 +1055,134 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
820
1055
  * @remarks Time O(log n) average, Space O(1)
821
1056
  * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
822
1057
  * @returns Array with deletion metadata (removed node, rebalancing hint if any).
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+
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
+
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
+
1139
+
1140
+
1141
+
1142
+
1143
+
1144
+
1145
+
1146
+
1147
+
1148
+
1149
+
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
+ * @example
1181
+ * // Remove and rebalance
1182
+ * const rbt = new RedBlackTree<number>([10, 5, 15, 3, 7]);
1183
+ * rbt.delete(5);
1184
+ * console.log(rbt.has(5)); // false;
1185
+ * console.log(rbt.size); // 4;
823
1186
  */
824
1187
  override delete(
825
1188
  keyNodeEntryRawOrPredicate: BTNRep<K, V, RedBlackTreeNode<K, V>> | NodePredicate<RedBlackTreeNode<K, V> | null>
@@ -842,39 +1205,38 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
842
1205
  const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : undefined;
843
1206
 
844
1207
  let originalColor = nodeToDelete.color;
845
- let replacementNode: RedBlackTreeNode<K, V> | undefined;
1208
+ const NIL = this.NIL;
1209
+ let replacementNode: RedBlackTreeNode<K, V> = NIL;
846
1210
 
847
1211
  if (!this.isRealNode(nodeToDelete.left)) {
848
- if (nodeToDelete.right !== null) {
849
- replacementNode = nodeToDelete.right;
850
- this._transplant(nodeToDelete, nodeToDelete.right);
851
- }
1212
+ // No real left child → replace with right (may be NIL)
1213
+ replacementNode = nodeToDelete.right ?? NIL;
1214
+ this._transplant(nodeToDelete, replacementNode);
852
1215
  } else if (!this.isRealNode(nodeToDelete.right)) {
1216
+ // No real right child → replace with left
853
1217
  replacementNode = nodeToDelete.left;
854
- this._transplant(nodeToDelete, nodeToDelete.left);
1218
+ this._transplant(nodeToDelete, replacementNode);
855
1219
  } else {
1220
+ // Two children → find in-order successor
856
1221
  const successor = this.getLeftMost(node => node, nodeToDelete.right);
857
1222
  if (successor) {
858
1223
  originalColor = successor.color;
859
- if (successor.right !== null) replacementNode = successor.right;
1224
+ replacementNode = successor.right ?? NIL;
860
1225
 
861
1226
  if (successor.parent === nodeToDelete) {
862
- if (this.isRealNode(replacementNode)) {
863
- replacementNode.parent = successor;
864
- }
1227
+ // Even if replacementNode is NIL, set its parent for fixup
1228
+ replacementNode.parent = successor;
865
1229
  } else {
866
- if (successor.right !== null) {
867
- this._transplant(successor, successor.right);
868
- successor.right = nodeToDelete.right;
869
- }
870
- if (this.isRealNode(successor.right)) {
1230
+ this._transplant(successor, replacementNode);
1231
+ successor.right = nodeToDelete.right;
1232
+ if (successor.right) {
871
1233
  successor.right.parent = successor;
872
1234
  }
873
1235
  }
874
1236
 
875
1237
  this._transplant(nodeToDelete, successor);
876
1238
  successor.left = nodeToDelete.left;
877
- if (this.isRealNode(successor.left)) {
1239
+ if (successor.left) {
878
1240
  successor.left.parent = successor;
879
1241
  }
880
1242
  successor.color = nodeToDelete.color;
@@ -923,8 +1285,101 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
923
1285
  * Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
924
1286
  * sorted bulk insert, which naturally produces a balanced RBT.
925
1287
  * @remarks Time O(N), Space O(N)
1288
+
1289
+
1290
+
1291
+
1292
+
1293
+
1294
+
1295
+
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+
1304
+
1305
+
1306
+
1307
+
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1315
+
1316
+
1317
+
1318
+
1319
+
1320
+
1321
+
1322
+
1323
+
1324
+
1325
+
1326
+
1327
+
1328
+
1329
+
1330
+
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+
1337
+
1338
+
1339
+
1340
+
1341
+
1342
+
1343
+
1344
+
1345
+
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1353
+
1354
+
1355
+
1356
+
1357
+
1358
+
1359
+
1360
+
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
1368
+
1369
+
1370
+
1371
+
1372
+
1373
+
1374
+
1375
+
1376
+ * @example
1377
+ * // Rebalance tree
1378
+ * const rbt = new RedBlackTree<number>([1, 2, 3, 4, 5]);
1379
+ * rbt.perfectlyBalance();
1380
+ * console.log(rbt.isAVLBalanced()); // true;
926
1381
  */
927
- override perfectlyBalance(iterationType?: IterationType): boolean {
1382
+ override perfectlyBalance(_iterationType?: IterationType): boolean {
928
1383
  // Extract sorted entries, clear, re-insert — RBT self-balances on insert
929
1384
  const entries: [K, V | undefined][] = [];
930
1385
  for (const [key, value] of this) entries.push([key, value]);
@@ -938,6 +1393,133 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
938
1393
  return true;
939
1394
  }
940
1395
 
1396
+ /**
1397
+ * Transform to new tree
1398
+
1399
+
1400
+
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+
1407
+
1408
+
1409
+
1410
+
1411
+
1412
+
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+
1421
+
1422
+
1423
+
1424
+
1425
+
1426
+
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+
1434
+
1435
+
1436
+
1437
+
1438
+
1439
+
1440
+
1441
+
1442
+
1443
+
1444
+
1445
+
1446
+
1447
+
1448
+
1449
+
1450
+
1451
+
1452
+
1453
+
1454
+
1455
+
1456
+
1457
+
1458
+
1459
+
1460
+
1461
+
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+
1471
+
1472
+
1473
+
1474
+
1475
+
1476
+
1477
+
1478
+
1479
+
1480
+
1481
+
1482
+
1483
+
1484
+
1485
+
1486
+
1487
+
1488
+
1489
+
1490
+
1491
+
1492
+
1493
+
1494
+
1495
+
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+
1511
+
1512
+
1513
+
1514
+
1515
+
1516
+
1517
+ * @example
1518
+ * // Transform to new tree
1519
+ * const rbt = new RedBlackTree<number, number>([[1, 10], [2, 20]]);
1520
+ * const doubled = rbt.map((v, k) => [k, (v ?? 0) * 2] as [number, number]);
1521
+ * console.log([...doubled.values()]); // [20, 40];
1522
+ */
941
1523
  override map<MK = K, MV = V, MR = any>(
942
1524
  callback: EntryCallback<K, V | undefined, [MK, MV]>,
943
1525
  options?: Partial<RedBlackTreeOptions<MK, MV, MR>>,
@@ -1151,66 +1733,76 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
1151
1733
  * @returns void
1152
1734
  */
1153
1735
  protected _deleteFixup(node: RedBlackTreeNode<K, V> | undefined): void {
1154
- if (!node || node === this.root || node.color === 'BLACK') {
1155
- if (node) {
1156
- node.color = 'BLACK';
1157
- }
1158
- return;
1159
- }
1736
+ // Standard CLRS RB-DELETE-FIXUP: restore black-height invariant.
1737
+ // `node` is the child that replaced the deleted node (may be NIL sentinel).
1738
+ // If RED → just recolor BLACK (trivial fix). If BLACK → double-black repair.
1739
+ if (!node) return;
1160
1740
 
1161
- while (node && node !== this.root && node.color === 'BLACK') {
1162
- const parent: RedBlackTreeNode<K, V> | undefined = node.parent;
1741
+ const NIL = this.NIL;
1742
+ let current: RedBlackTreeNode<K, V> = node;
1163
1743
 
1164
- if (!parent) {
1165
- break;
1166
- }
1744
+ while (current !== this.root && current.color === 'BLACK') {
1745
+ const parent: RedBlackTreeNode<K, V> | undefined = current.parent;
1746
+ if (!parent) break;
1167
1747
 
1168
- if (node === parent.left) {
1169
- let sibling = parent.right;
1748
+ const nodeIsLeft = current === parent.left;
1749
+ let sibling = nodeIsLeft ? parent.right : parent.left;
1170
1750
 
1171
- if (sibling?.color === 'RED') {
1172
- sibling.color = 'BLACK';
1173
- parent.color = 'RED';
1751
+ // Case 1: sibling is RED → rotate to get a BLACK sibling
1752
+ if (sibling && sibling.color === 'RED') {
1753
+ sibling.color = 'BLACK';
1754
+ parent.color = 'RED';
1755
+ if (nodeIsLeft) {
1174
1756
  this._leftRotate(parent);
1175
1757
  sibling = parent.right;
1176
- }
1177
-
1178
- if ((sibling?.left?.color ?? 'BLACK') === 'BLACK') {
1179
- if (sibling) sibling.color = 'RED';
1180
- node = parent;
1181
1758
  } else {
1182
- if (sibling?.left) sibling.left.color = 'BLACK';
1183
- if (sibling) sibling.color = parent.color;
1184
- parent.color = 'BLACK';
1185
1759
  this._rightRotate(parent);
1186
- node = this.root;
1760
+ sibling = parent.left;
1187
1761
  }
1188
- } else {
1189
- let sibling = parent.left;
1762
+ }
1190
1763
 
1191
- if (sibling?.color === 'RED') {
1192
- sibling.color = 'BLACK';
1193
- if (parent) parent.color = 'RED';
1194
- this._rightRotate(parent);
1195
- if (parent) sibling = parent.left;
1196
- }
1764
+ const sibLeft = sibling?.left;
1765
+ const sibRight = sibling?.right;
1766
+ const sibLeftBlack = !sibLeft || sibLeft === NIL || sibLeft.color === 'BLACK';
1767
+ const sibRightBlack = !sibRight || sibRight === NIL || sibRight.color === 'BLACK';
1197
1768
 
1198
- if ((sibling?.right?.color ?? 'BLACK') === 'BLACK') {
1199
- if (sibling) sibling.color = 'RED';
1200
- node = parent;
1201
- } else {
1202
- if (sibling?.right) sibling.right.color = 'BLACK';
1769
+ if (sibLeftBlack && sibRightBlack) {
1770
+ // Case 2: sibling's children are both BLACK → recolor sibling RED, move up
1771
+ if (sibling) sibling.color = 'RED';
1772
+ current = parent;
1773
+ } else {
1774
+ if (nodeIsLeft) {
1775
+ // Case 3: sibling's right child is BLACK → rotate sibling right first
1776
+ if (sibRightBlack) {
1777
+ if (sibLeft) sibLeft.color = 'BLACK';
1778
+ if (sibling) sibling.color = 'RED';
1779
+ if (sibling) this._rightRotate(sibling);
1780
+ sibling = parent.right;
1781
+ }
1782
+ // Case 4: sibling's right child is RED → final rotation
1203
1783
  if (sibling) sibling.color = parent.color;
1204
- if (parent) parent.color = 'BLACK';
1784
+ parent.color = 'BLACK';
1785
+ if (sibling?.right) sibling.right.color = 'BLACK';
1205
1786
  this._leftRotate(parent);
1206
- node = this.root;
1787
+ } else {
1788
+ // Case 3 (mirror): sibling's left child is BLACK → rotate sibling left first
1789
+ if (sibLeftBlack) {
1790
+ if (sibRight) sibRight.color = 'BLACK';
1791
+ if (sibling) sibling.color = 'RED';
1792
+ if (sibling) this._leftRotate(sibling);
1793
+ sibling = parent.left;
1794
+ }
1795
+ // Case 4 (mirror): sibling's left child is RED → final rotation
1796
+ if (sibling) sibling.color = parent.color;
1797
+ parent.color = 'BLACK';
1798
+ if (sibling?.left) sibling.left.color = 'BLACK';
1799
+ this._rightRotate(parent);
1207
1800
  }
1801
+ current = this.root!;
1208
1802
  }
1209
1803
  }
1210
1804
 
1211
- if (node) {
1212
- node.color = 'BLACK';
1213
- }
1805
+ current.color = 'BLACK';
1214
1806
  }
1215
1807
 
1216
1808
  /**