red-black-tree-typed 2.4.0 → 2.4.2

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 (56) hide show
  1. package/dist/cjs/index.cjs +587 -93
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs-legacy/index.cjs +593 -98
  4. package/dist/cjs-legacy/index.cjs.map +1 -1
  5. package/dist/esm/index.mjs +587 -93
  6. package/dist/esm/index.mjs.map +1 -1
  7. package/dist/esm-legacy/index.mjs +593 -98
  8. package/dist/esm-legacy/index.mjs.map +1 -1
  9. package/dist/types/data-structures/base/linear-base.d.ts +6 -6
  10. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +6 -6
  11. package/dist/types/data-structures/binary-tree/bst.d.ts +2 -1
  12. package/dist/types/data-structures/binary-tree/index.d.ts +3 -3
  13. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +150 -20
  14. package/dist/types/data-structures/binary-tree/tree-map.d.ts +188 -0
  15. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +238 -147
  16. package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +270 -0
  17. package/dist/types/data-structures/binary-tree/tree-set.d.ts +181 -0
  18. package/dist/types/interfaces/binary-tree.d.ts +2 -2
  19. package/dist/types/types/data-structures/binary-tree/index.d.ts +3 -3
  20. package/dist/types/types/data-structures/binary-tree/tree-map.d.ts +33 -0
  21. package/dist/types/types/data-structures/binary-tree/tree-multi-set.d.ts +16 -0
  22. package/dist/types/types/data-structures/binary-tree/tree-set.d.ts +33 -0
  23. package/dist/umd/red-black-tree-typed.js +593 -98
  24. package/dist/umd/red-black-tree-typed.js.map +1 -1
  25. package/dist/umd/red-black-tree-typed.min.js +3 -3
  26. package/dist/umd/red-black-tree-typed.min.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/data-structures/base/linear-base.ts +2 -12
  29. package/src/data-structures/binary-tree/avl-tree.ts +1 -1
  30. package/src/data-structures/binary-tree/binary-tree.ts +45 -21
  31. package/src/data-structures/binary-tree/bst.ts +85 -10
  32. package/src/data-structures/binary-tree/index.ts +3 -3
  33. package/src/data-structures/binary-tree/red-black-tree.ts +568 -76
  34. package/src/data-structures/binary-tree/tree-map.ts +439 -0
  35. package/src/data-structures/binary-tree/tree-multi-map.ts +488 -325
  36. package/src/data-structures/binary-tree/tree-multi-set.ts +502 -0
  37. package/src/data-structures/binary-tree/tree-set.ts +407 -0
  38. package/src/data-structures/queue/deque.ts +10 -0
  39. package/src/data-structures/trie/trie.ts +6 -8
  40. package/src/interfaces/binary-tree.ts +2 -2
  41. package/src/types/data-structures/binary-tree/index.ts +3 -3
  42. package/src/types/data-structures/binary-tree/tree-map.ts +45 -0
  43. package/src/types/data-structures/binary-tree/tree-multi-set.ts +19 -0
  44. package/src/types/data-structures/binary-tree/tree-set.ts +39 -0
  45. package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +0 -236
  46. package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +0 -197
  47. package/dist/types/data-structures/binary-tree/tree-counter.d.ts +0 -243
  48. package/dist/types/types/data-structures/binary-tree/avl-tree-counter.d.ts +0 -2
  49. package/dist/types/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +0 -2
  50. package/dist/types/types/data-structures/binary-tree/tree-counter.d.ts +0 -2
  51. package/src/data-structures/binary-tree/avl-tree-counter.ts +0 -539
  52. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +0 -438
  53. package/src/data-structures/binary-tree/tree-counter.ts +0 -575
  54. package/src/types/data-structures/binary-tree/avl-tree-counter.ts +0 -3
  55. package/src/types/data-structures/binary-tree/avl-tree-multi-map.ts +0 -3
  56. package/src/types/data-structures/binary-tree/tree-counter.ts +0 -3
@@ -1231,6 +1231,9 @@ var BinaryTree = class extends IterableEntryBase {
1231
1231
  get isDuplicate() {
1232
1232
  return this._isDuplicate;
1233
1233
  }
1234
+ // Map mode acceleration store:
1235
+ // - isMapMode=false: unused
1236
+ // - isMapMode=true: key -> node reference (O(1) has/getNode + fast get)
1234
1237
  _store = /* @__PURE__ */ new Map();
1235
1238
  /**
1236
1239
  * Gets the external value store (used in Map mode).
@@ -1290,7 +1293,7 @@ var BinaryTree = class extends IterableEntryBase {
1290
1293
  * @returns The newly created node.
1291
1294
  */
1292
1295
  createNode(key, value) {
1293
- return new BinaryTreeNode(key, this._isMapMode ? void 0 : value);
1296
+ return new BinaryTreeNode(key, value);
1294
1297
  }
1295
1298
  /**
1296
1299
  * Creates a new, empty tree of the same type and configuration.
@@ -1437,11 +1440,11 @@ var BinaryTree = class extends IterableEntryBase {
1437
1440
  * @returns True if the addition was successful, false otherwise.
1438
1441
  */
1439
1442
  set(keyNodeOrEntry, value) {
1440
- const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
1443
+ const [newNode] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
1441
1444
  if (newNode === void 0) return false;
1442
1445
  if (!this._root) {
1443
1446
  this._setRoot(newNode);
1444
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
1447
+ if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
1445
1448
  this._size = 1;
1446
1449
  return true;
1447
1450
  }
@@ -1453,7 +1456,7 @@ var BinaryTree = class extends IterableEntryBase {
1453
1456
  if (!this._isDuplicate) {
1454
1457
  if (newNode !== null && cur.key === newNode.key) {
1455
1458
  this._replaceNode(cur, newNode);
1456
- if (this._isMapMode) this._setValue(cur.key, newValue);
1459
+ if (this._isMapMode && newNode !== null) this._store.set(cur.key, newNode);
1457
1460
  return true;
1458
1461
  }
1459
1462
  }
@@ -1473,7 +1476,7 @@ var BinaryTree = class extends IterableEntryBase {
1473
1476
  } else if (potentialParent.right === void 0) {
1474
1477
  potentialParent.right = newNode;
1475
1478
  }
1476
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
1479
+ if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
1477
1480
  this._size++;
1478
1481
  return true;
1479
1482
  }
@@ -1540,13 +1543,13 @@ var BinaryTree = class extends IterableEntryBase {
1540
1543
  * Deletes a node from the tree.
1541
1544
  * @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). This implementation finds the node, and if it has two children, swaps it with the rightmost node of its left subtree (in-order predecessor) before deleting. Time O(N) in the worst case. O(N) to find the node (`getNode`) and O(H) (which is O(N) worst-case) to find the rightmost node. Space O(1) (if `getNode` is iterative, which it is).
1542
1545
  *
1543
- * @param keyNodeOrEntry - The node to delete.
1546
+ * @param keyNodeEntryRawOrPredicate - The node to delete.
1544
1547
  * @returns An array containing deletion results (for compatibility with self-balancing trees).
1545
1548
  */
1546
- delete(keyNodeOrEntry) {
1549
+ delete(keyNodeEntryRawOrPredicate) {
1547
1550
  const deletedResult = [];
1548
1551
  if (!this._root) return deletedResult;
1549
- const curr = this.getNode(keyNodeOrEntry);
1552
+ const curr = this.getNode(keyNodeEntryRawOrPredicate);
1550
1553
  if (!curr) return deletedResult;
1551
1554
  const parent = curr?.parent;
1552
1555
  let needBalanced;
@@ -1558,6 +1561,10 @@ var BinaryTree = class extends IterableEntryBase {
1558
1561
  if (leftSubTreeRightMost) {
1559
1562
  const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
1560
1563
  orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
1564
+ if (this._isMapMode) {
1565
+ this._store.set(curr.key, curr);
1566
+ this._store.set(leftSubTreeRightMost.key, leftSubTreeRightMost);
1567
+ }
1561
1568
  if (parentOfLeftSubTreeMax) {
1562
1569
  if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
1563
1570
  parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
@@ -1641,6 +1648,13 @@ var BinaryTree = class extends IterableEntryBase {
1641
1648
  * @returns The first matching node, or undefined if not found.
1642
1649
  */
1643
1650
  getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
1651
+ if (this._isMapMode && keyNodeEntryOrPredicate !== null && keyNodeEntryOrPredicate !== void 0) {
1652
+ if (!this._isPredicate(keyNodeEntryOrPredicate)) {
1653
+ const key = this._extractKey(keyNodeEntryOrPredicate);
1654
+ if (key === null || key === void 0) return;
1655
+ return this._store.get(key);
1656
+ }
1657
+ }
1644
1658
  return this.search(keyNodeEntryOrPredicate, true, (node) => node, startNode, iterationType)[0];
1645
1659
  }
1646
1660
  /**
@@ -1656,11 +1670,18 @@ var BinaryTree = class extends IterableEntryBase {
1656
1670
  if (this._isMapMode) {
1657
1671
  const key = this._extractKey(keyNodeEntryOrPredicate);
1658
1672
  if (key === null || key === void 0) return;
1659
- return this._store.get(key);
1673
+ return this._store.get(key)?.value;
1660
1674
  }
1661
1675
  return this.getNode(keyNodeEntryOrPredicate, startNode, iterationType)?.value;
1662
1676
  }
1663
1677
  has(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
1678
+ if (this._isMapMode && keyNodeEntryOrPredicate !== void 0 && keyNodeEntryOrPredicate !== null) {
1679
+ if (!this._isPredicate(keyNodeEntryOrPredicate)) {
1680
+ const key = this._extractKey(keyNodeEntryOrPredicate);
1681
+ if (key === null || key === void 0) return false;
1682
+ return this._store.has(key);
1683
+ }
1684
+ }
1664
1685
  return this.search(keyNodeEntryOrPredicate, true, (node) => node, startNode, iterationType).length > 0;
1665
1686
  }
1666
1687
  /**
@@ -1729,7 +1750,7 @@ var BinaryTree = class extends IterableEntryBase {
1729
1750
  }
1730
1751
  return true;
1731
1752
  }, "checkBST");
1732
- const isStandardBST = checkBST(false);
1753
+ const isStandardBST = checkBST();
1733
1754
  const isInverseBST = checkBST(true);
1734
1755
  return isStandardBST || isInverseBST;
1735
1756
  }
@@ -2403,8 +2424,7 @@ var BinaryTree = class extends IterableEntryBase {
2403
2424
  }
2404
2425
  current = stack.pop();
2405
2426
  if (this.isRealNode(current)) {
2406
- if (this._isMapMode) yield [current.key, this._store.get(current.key)];
2407
- else yield [current.key, current.value];
2427
+ yield [current.key, current.value];
2408
2428
  current = current.right;
2409
2429
  }
2410
2430
  }
@@ -2412,8 +2432,7 @@ var BinaryTree = class extends IterableEntryBase {
2412
2432
  if (node.left && this.isRealNode(node)) {
2413
2433
  yield* this[Symbol.iterator](node.left);
2414
2434
  }
2415
- if (this._isMapMode) yield [node.key, this._store.get(node.key)];
2416
- else yield [node.key, node.value];
2435
+ yield [node.key, node.value];
2417
2436
  if (node.right && this.isRealNode(node)) {
2418
2437
  yield* this[Symbol.iterator](node.right);
2419
2438
  }
@@ -2499,8 +2518,7 @@ var BinaryTree = class extends IterableEntryBase {
2499
2518
  (node) => {
2500
2519
  if (node === null) cloned.set(null);
2501
2520
  else {
2502
- if (this._isMapMode) cloned.set([node.key, this._store.get(node.key)]);
2503
- else cloned.set([node.key, node.value]);
2521
+ cloned.set([node.key, node.value]);
2504
2522
  }
2505
2523
  },
2506
2524
  this._root,
@@ -2508,7 +2526,6 @@ var BinaryTree = class extends IterableEntryBase {
2508
2526
  true
2509
2527
  // Include nulls
2510
2528
  );
2511
- if (this._isMapMode) cloned._store = this._store;
2512
2529
  }
2513
2530
  /**
2514
2531
  * (Protected) Recursive helper for `toVisual`.
@@ -2671,8 +2688,10 @@ var BinaryTree = class extends IterableEntryBase {
2671
2688
  */
2672
2689
  _setValue(key, value) {
2673
2690
  if (key === null || key === void 0) return false;
2674
- if (value === void 0) return false;
2675
- return this._store.set(key, value);
2691
+ const node = this._store.get(key);
2692
+ if (!node) return false;
2693
+ node.value = value;
2694
+ return true;
2676
2695
  }
2677
2696
  /**
2678
2697
  * (Protected) Clears all nodes from the tree.
@@ -2883,7 +2902,7 @@ var BST = class extends BinaryTree {
2883
2902
  * @returns The newly created BSTNode.
2884
2903
  */
2885
2904
  createNode(key, value) {
2886
- return new BSTNode(key, this._isMapMode ? void 0 : value);
2905
+ return new BSTNode(key, value);
2887
2906
  }
2888
2907
  /**
2889
2908
  * Ensures the input is a node. If it's a key or entry, it searches for the node.
@@ -2967,7 +2986,39 @@ var BST = class extends BinaryTree {
2967
2986
  * @returns The first matching node, or undefined if not found.
2968
2987
  */
2969
2988
  getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
2970
- return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
2989
+ if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === void 0) return void 0;
2990
+ if (this._isPredicate(keyNodeEntryOrPredicate)) {
2991
+ return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
2992
+ }
2993
+ if (keyNodeEntryOrPredicate instanceof Range) {
2994
+ return this.getNodes(
2995
+ keyNodeEntryOrPredicate,
2996
+ true,
2997
+ startNode,
2998
+ iterationType
2999
+ )[0] ?? void 0;
3000
+ }
3001
+ let targetKey;
3002
+ if (this.isNode(keyNodeEntryOrPredicate)) {
3003
+ targetKey = keyNodeEntryOrPredicate.key;
3004
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
3005
+ const k = keyNodeEntryOrPredicate[0];
3006
+ if (k === null || k === void 0) return void 0;
3007
+ targetKey = k;
3008
+ } else {
3009
+ targetKey = keyNodeEntryOrPredicate;
3010
+ }
3011
+ const start = this.ensureNode(startNode);
3012
+ if (!start) return void 0;
3013
+ const NIL = this._NIL;
3014
+ let cur = start;
3015
+ const cmpFn = this._comparator;
3016
+ while (cur && cur !== NIL) {
3017
+ const c = cmpFn(targetKey, cur.key);
3018
+ if (c === 0) return cur;
3019
+ cur = c < 0 ? cur._left : cur._right;
3020
+ }
3021
+ return void 0;
2971
3022
  }
2972
3023
  /**
2973
3024
  * Searches the tree for nodes matching a predicate, key, or range.
@@ -2988,8 +3039,30 @@ var BST = class extends BinaryTree {
2988
3039
  if (keyNodeEntryOrPredicate === null) return [];
2989
3040
  startNode = this.ensureNode(startNode);
2990
3041
  if (!startNode) return [];
2991
- let predicate;
2992
3042
  const isRange = this.isRange(keyNodeEntryOrPredicate);
3043
+ const isPred = !isRange && this._isPredicate(keyNodeEntryOrPredicate);
3044
+ if (!isRange && !isPred) {
3045
+ let targetKey;
3046
+ if (this.isNode(keyNodeEntryOrPredicate)) {
3047
+ targetKey = keyNodeEntryOrPredicate.key;
3048
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
3049
+ const k = keyNodeEntryOrPredicate[0];
3050
+ if (k !== null && k !== void 0) targetKey = k;
3051
+ } else {
3052
+ targetKey = keyNodeEntryOrPredicate;
3053
+ }
3054
+ if (targetKey === void 0) return [];
3055
+ const NIL = this._NIL;
3056
+ const cmpFn = this._comparator;
3057
+ let cur = startNode;
3058
+ while (cur && cur !== NIL) {
3059
+ const c = cmpFn(targetKey, cur.key);
3060
+ if (c === 0) return [callback(cur)];
3061
+ cur = c < 0 ? cur._left : cur._right;
3062
+ }
3063
+ return [];
3064
+ }
3065
+ let predicate;
2993
3066
  if (isRange) {
2994
3067
  predicate = /* @__PURE__ */ __name((node) => {
2995
3068
  if (!node) return false;
@@ -3068,11 +3141,11 @@ var BST = class extends BinaryTree {
3068
3141
  * @returns True if the addition was successful, false otherwise.
3069
3142
  */
3070
3143
  set(keyNodeOrEntry, value) {
3071
- const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
3144
+ const [newNode] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
3072
3145
  if (newNode === void 0) return false;
3073
3146
  if (this._root === void 0) {
3074
3147
  this._setRoot(newNode);
3075
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3148
+ if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
3076
3149
  this._size++;
3077
3150
  return true;
3078
3151
  }
@@ -3080,12 +3153,12 @@ var BST = class extends BinaryTree {
3080
3153
  while (current !== void 0) {
3081
3154
  if (this._compare(current.key, newNode.key) === 0) {
3082
3155
  this._replaceNode(current, newNode);
3083
- if (this._isMapMode) this._setValue(current.key, newValue);
3156
+ if (this._isMapMode && this.isRealNode(newNode)) this._store.set(current.key, newNode);
3084
3157
  return true;
3085
3158
  } else if (this._compare(current.key, newNode.key) > 0) {
3086
3159
  if (current.left === void 0) {
3087
3160
  current.left = newNode;
3088
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3161
+ if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
3089
3162
  this._size++;
3090
3163
  return true;
3091
3164
  }
@@ -3093,7 +3166,7 @@ var BST = class extends BinaryTree {
3093
3166
  } else {
3094
3167
  if (current.right === void 0) {
3095
3168
  current.right = newNode;
3096
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3169
+ if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
3097
3170
  this._size++;
3098
3171
  return true;
3099
3172
  }
@@ -3911,7 +3984,7 @@ var BST = class extends BinaryTree {
3911
3984
  succ.left = node.left;
3912
3985
  if (succ.left) succ.left.parent = succ;
3913
3986
  }
3914
- this._size = Math.max(0, (this._size ?? 0) - 1);
3987
+ this._size = Math.max(0, this._size - 1);
3915
3988
  return true;
3916
3989
  }
3917
3990
  };
@@ -3925,12 +3998,11 @@ var RedBlackTreeNode = class {
3925
3998
  value;
3926
3999
  parent = void 0;
3927
4000
  /**
3928
- * Create a Red-Black Tree and optionally bulk-insert items.
3929
- * @remarks Time O(n log n), Space O(n)
3930
- * @param key - See parameter type for details.
3931
- * @param [value]- See parameter type for details.
3932
- * @param color - See parameter type for details.
3933
- * @returns New RedBlackTree instance.
4001
+ * Create a Red-Black Tree node.
4002
+ * @remarks Time O(1), Space O(1)
4003
+ * @param key - Node key.
4004
+ * @param [value] - Node value (unused in map mode trees).
4005
+ * @param color - Node color.
3934
4006
  */
3935
4007
  constructor(key, value, color = "BLACK") {
3936
4008
  this.key = key;
@@ -4061,11 +4133,33 @@ var RedBlackTree = class extends BST {
4061
4133
  constructor(keysNodesEntriesOrRaws = [], options) {
4062
4134
  super([], options);
4063
4135
  this._root = this.NIL;
4136
+ this._header = new RedBlackTreeNode(void 0, void 0, "BLACK");
4137
+ this._header.parent = this.NIL;
4138
+ this._header._left = this.NIL;
4139
+ this._header._right = this.NIL;
4064
4140
  if (keysNodesEntriesOrRaws) {
4065
4141
  this.setMany(keysNodesEntriesOrRaws);
4066
4142
  }
4067
4143
  }
4068
4144
  _root;
4145
+ /**
4146
+ * (Internal) Header sentinel:
4147
+ * - header.parent -> root
4148
+ * - header._left -> min (or NIL)
4149
+ * - header._right -> max (or NIL)
4150
+ *
4151
+ * IMPORTANT:
4152
+ * - This header is NOT part of the actual tree.
4153
+ * - Do NOT use `header.left` / `header.right` accessors for wiring: those setters update `NIL.parent`
4154
+ * and can corrupt sentinel invariants / cause hangs. Only touch `header._left/_right`.
4155
+ */
4156
+ _header;
4157
+ /**
4158
+ * (Internal) Cache of the current minimum and maximum nodes.
4159
+ * Used for fast-path insert/update when keys are monotonic or near-boundary.
4160
+ */
4161
+ _minNode;
4162
+ _maxNode;
4069
4163
  /**
4070
4164
  * Get the current root node.
4071
4165
  * @remarks Time O(1), Space O(1)
@@ -4083,7 +4177,7 @@ var RedBlackTree = class extends BST {
4083
4177
  * @returns A new RedBlackTreeNode instance.
4084
4178
  */
4085
4179
  createNode(key, value, color = "BLACK") {
4086
- return new RedBlackTreeNode(key, this._isMapMode ? void 0 : value, color);
4180
+ return new RedBlackTreeNode(key, value, color);
4087
4181
  }
4088
4182
  /**
4089
4183
  * Type guard: check whether the input is a RedBlackTreeNode.
@@ -4099,18 +4193,357 @@ var RedBlackTree = class extends BST {
4099
4193
  * @remarks Time O(n), Space O(1)
4100
4194
  * @returns void
4101
4195
  */
4196
+ /**
4197
+ * Remove all nodes and clear internal caches.
4198
+ * @remarks Time O(n) average, Space O(1)
4199
+ */
4102
4200
  clear() {
4103
4201
  super.clear();
4104
4202
  this._root = this.NIL;
4203
+ this._header.parent = this.NIL;
4204
+ this._setMinCache(void 0);
4205
+ this._setMaxCache(void 0);
4105
4206
  }
4106
4207
  /**
4107
- * Insert or replace an entry using BST order and red-black fix-up.
4108
- * @remarks Time O(log n), Space O(1)
4109
- * @param keyNodeOrEntry - Key, node, or [key, value] entry to insert.
4110
- * @param [value]- See parameter type for details.
4111
- * @returns True if inserted or updated; false if ignored.
4208
+ * (Internal) Find a node by key using a tight BST walk (no allocations).
4209
+ *
4210
+ * NOTE: This uses `header.parent` as the canonical root pointer.
4211
+ * @remarks Time O(log n) average, Space O(1)
4212
+ */
4213
+ _findNodeByKey(key) {
4214
+ const NIL = this.NIL;
4215
+ const cmp = this._compare.bind(this);
4216
+ let cur = this._header.parent ?? NIL;
4217
+ while (cur !== NIL) {
4218
+ const c = cmp(key, cur.key);
4219
+ if (c < 0) cur = cur.left ?? NIL;
4220
+ else if (c > 0) cur = cur.right ?? NIL;
4221
+ else return cur;
4222
+ }
4223
+ return void 0;
4224
+ }
4225
+ /**
4226
+ * (Internal) In-order predecessor of a node in a BST.
4227
+ * @remarks Time O(log n) average, Space O(1)
4228
+ */
4229
+ _predecessorOf(node) {
4230
+ const NIL = this.NIL;
4231
+ if (node.left && node.left !== NIL) {
4232
+ let cur2 = node.left;
4233
+ while (cur2.right && cur2.right !== NIL) cur2 = cur2.right;
4234
+ return cur2;
4235
+ }
4236
+ let cur = node;
4237
+ let p = node.parent;
4238
+ while (p && cur === p.left) {
4239
+ cur = p;
4240
+ p = p.parent;
4241
+ }
4242
+ return p;
4243
+ }
4244
+ /**
4245
+ * (Internal) In-order successor of a node in a BST.
4246
+ * @remarks Time O(log n) average, Space O(1)
4247
+ */
4248
+ _successorOf(node) {
4249
+ const NIL = this.NIL;
4250
+ if (node.right && node.right !== NIL) {
4251
+ let cur2 = node.right;
4252
+ while (cur2.left && cur2.left !== NIL) cur2 = cur2.left;
4253
+ return cur2;
4254
+ }
4255
+ let cur = node;
4256
+ let p = node.parent;
4257
+ while (p && cur === p.right) {
4258
+ cur = p;
4259
+ p = p.parent;
4260
+ }
4261
+ return p;
4262
+ }
4263
+ /**
4264
+ * (Internal) Attach a new node directly under a known parent/side (no search).
4265
+ *
4266
+ * This is a performance-oriented helper used by boundary fast paths and hinted insertion.
4267
+ * It will:
4268
+ * - wire parent/child pointers (using accessors, so parent pointers are updated)
4269
+ * - initialize children to NIL
4270
+ * - mark the new node RED, then run insert fix-up
4271
+ *
4272
+ * Precondition: the chosen slot (parent.left/parent.right) is empty (NIL/null/undefined).
4273
+ * @remarks Time O(log n) average, Space O(1)
4274
+ */
4275
+ _attachNewNode(parent, side, node) {
4276
+ const NIL = this.NIL;
4277
+ node.parent = parent;
4278
+ if (side === "left") parent.left = node;
4279
+ else parent.right = node;
4280
+ node.left = NIL;
4281
+ node.right = NIL;
4282
+ node.color = "RED";
4283
+ this._insertFixup(node);
4284
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
4285
+ }
4286
+ /**
4287
+ * (Internal) a single source of truth for min/max is header._left/_right.
4288
+ * Keep legacy _minNode/_maxNode mirrored for compatibility.
4289
+ * @remarks Time O(1), Space O(1)
4290
+ */
4291
+ /**
4292
+ * (Internal) Update min cache pointers (header._left is the canonical min pointer).
4293
+ * @remarks Time O(1), Space O(1)
4294
+ */
4295
+ _setMinCache(node) {
4296
+ this._minNode = node;
4297
+ this._header._left = node ?? this.NIL;
4298
+ }
4299
+ /**
4300
+ * (Internal) Update max cache pointers (header._right is the canonical max pointer).
4301
+ * @remarks Time O(1), Space O(1)
4302
+ */
4303
+ _setMaxCache(node) {
4304
+ this._maxNode = node;
4305
+ this._header._right = node ?? this.NIL;
4306
+ }
4307
+ /**
4308
+ * (Internal) Core set implementation returning the affected node.
4309
+ *
4310
+ * Hot path goals:
4311
+ * - Avoid double walks (search+insert): do a single traversal that either updates or inserts.
4312
+ * - Use header min/max caches to fast-path boundary inserts.
4313
+ * - Keep header._left/_right as canonical min/max pointers.
4314
+ *
4315
+ * Return value:
4316
+ * - `{ node, created:false }` when an existing key is updated
4317
+ * - `{ node, created:true }` when a new node is inserted
4318
+ * - `undefined` only on unexpected internal failure.
4319
+ * @remarks Time O(log n) average, Space O(1)
4320
+ */
4321
+ _setKVNode(key, nextValue) {
4322
+ const NIL = this.NIL;
4323
+ const comparator = this._comparator;
4324
+ const header = this._header;
4325
+ const minN = header._left ?? NIL;
4326
+ if (minN !== NIL) {
4327
+ const cMin = comparator(key, minN.key);
4328
+ if (cMin === 0) {
4329
+ minN.value = nextValue;
4330
+ if (this._isMapMode) this._store.set(key, minN);
4331
+ return { node: minN, created: false };
4332
+ }
4333
+ const minL = minN.left;
4334
+ if (cMin < 0 && (minL === NIL || minL === null || minL === void 0)) {
4335
+ const newNode2 = this.createNode(key, nextValue);
4336
+ this._attachNewNode(minN, "left", newNode2);
4337
+ if (this._isMapMode) this._store.set(newNode2.key, newNode2);
4338
+ this._size++;
4339
+ this._setMinCache(newNode2);
4340
+ if (header._right === NIL) this._setMaxCache(newNode2);
4341
+ return { node: newNode2, created: true };
4342
+ }
4343
+ if (cMin > 0) {
4344
+ const maxN = header._right ?? NIL;
4345
+ const cMax = comparator(key, maxN.key);
4346
+ if (cMax === 0) {
4347
+ maxN.value = nextValue;
4348
+ if (this._isMapMode) this._store.set(key, maxN);
4349
+ return { node: maxN, created: false };
4350
+ }
4351
+ const maxR = maxN.right;
4352
+ if (cMax > 0 && (maxR === NIL || maxR === null || maxR === void 0)) {
4353
+ const newNode2 = this.createNode(key, nextValue);
4354
+ this._attachNewNode(maxN, "right", newNode2);
4355
+ if (this._isMapMode) this._store.set(newNode2.key, newNode2);
4356
+ this._size++;
4357
+ this._setMaxCache(newNode2);
4358
+ if (header._left === NIL) this._setMinCache(newNode2);
4359
+ return { node: newNode2, created: true };
4360
+ }
4361
+ }
4362
+ }
4363
+ const cmp = comparator;
4364
+ const isMapMode = this._isMapMode;
4365
+ const store = this._store;
4366
+ let current = this._header.parent ?? NIL;
4367
+ let parent;
4368
+ let lastCompared = 0;
4369
+ while (current !== NIL) {
4370
+ parent = current;
4371
+ lastCompared = cmp(key, current.key);
4372
+ if (lastCompared < 0) current = current.left ?? NIL;
4373
+ else if (lastCompared > 0) current = current.right ?? NIL;
4374
+ else {
4375
+ current.value = nextValue;
4376
+ if (isMapMode) store.set(key, current);
4377
+ return { node: current, created: false };
4378
+ }
4379
+ }
4380
+ const newNode = this.createNode(key, nextValue);
4381
+ newNode.parent = parent;
4382
+ if (!parent) {
4383
+ this._setRoot(newNode);
4384
+ } else if (lastCompared < 0) {
4385
+ parent.left = newNode;
4386
+ } else {
4387
+ parent.right = newNode;
4388
+ }
4389
+ newNode.left = NIL;
4390
+ newNode.right = NIL;
4391
+ newNode.color = "RED";
4392
+ this._insertFixup(newNode);
4393
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
4394
+ else return void 0;
4395
+ if (isMapMode) store.set(newNode.key, newNode);
4396
+ this._size++;
4397
+ const hMin = this._header._left ?? NIL;
4398
+ const hMax = this._header._right ?? NIL;
4399
+ if (hMin === NIL || hMax === NIL) {
4400
+ this._setMinCache(newNode);
4401
+ this._setMaxCache(newNode);
4402
+ } else if (parent === hMax && lastCompared > 0) {
4403
+ this._setMaxCache(newNode);
4404
+ } else if (parent === hMin && lastCompared < 0) {
4405
+ this._setMinCache(newNode);
4406
+ } else {
4407
+ if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
4408
+ if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
4409
+ }
4410
+ return { node: newNode, created: true };
4411
+ }
4412
+ /**
4413
+ * (Internal) Boolean wrapper around `_setKVNode`.
4414
+ *
4415
+ * Includes a map-mode update fast-path:
4416
+ * - If `isMapMode=true` and the key already exists in `_store`, then updating the value does not
4417
+ * require any tree search/rotation (tree shape depends only on key).
4418
+ * - This path is intentionally limited to `nextValue !== undefined` to preserve existing
4419
+ * semantics for `undefined` values.
4420
+ * @remarks Time O(log n) average, Space O(1)
4421
+ */
4422
+ _setKV(key, nextValue) {
4423
+ if (this._isMapMode) {
4424
+ const store = this._store;
4425
+ const node = store.get(key);
4426
+ if (node) {
4427
+ node.value = nextValue;
4428
+ return true;
4429
+ }
4430
+ }
4431
+ return this._setKVNode(key, nextValue) !== void 0;
4432
+ }
4433
+ /**
4434
+ * Insert/update using a hint node to speed up nearby insertions.
4435
+ *
4436
+ * close to the expected insertion position (often the previously returned node in a loop).
4437
+ *
4438
+ * When the hint is a good fit (sorted / nearly-sorted insertion), this can avoid most of the
4439
+ * normal root-to-leaf search and reduce constant factors.
4440
+ *
4441
+ * When the hint does not match (random workloads), this will fall back to the normal set path.
4442
+ * @remarks Time O(log n) average, Space O(1)
4443
+ */
4444
+ setWithHintNode(key, value, hint) {
4445
+ if (!hint || !this.isRealNode(hint)) {
4446
+ return this._setKVNode(key, value)?.node;
4447
+ }
4448
+ const cmp = this._compare.bind(this);
4449
+ const c0 = cmp(key, hint.key);
4450
+ if (c0 === 0) {
4451
+ hint.value = value;
4452
+ if (this._isMapMode) this._store.set(key, hint);
4453
+ return hint;
4454
+ }
4455
+ if (c0 < 0) {
4456
+ if (!this.isRealNode(hint.left)) {
4457
+ const newNode = this.createNode(key, value);
4458
+ if (!this.isRealNode(newNode)) return void 0;
4459
+ this._attachNewNode(hint, "left", newNode);
4460
+ if (this._isMapMode) this._store.set(key, newNode);
4461
+ this._size++;
4462
+ const NIL = this.NIL;
4463
+ const hMin = this._header._left ?? NIL;
4464
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
4465
+ const hMax = this._header._right ?? NIL;
4466
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
4467
+ return newNode;
4468
+ }
4469
+ const pred = this._predecessorOf(hint);
4470
+ if (pred && cmp(pred.key, key) >= 0) {
4471
+ return this._setKVNode(key, value)?.node;
4472
+ }
4473
+ if (pred && !this.isRealNode(pred.right)) {
4474
+ const newNode = this.createNode(key, value);
4475
+ if (!this.isRealNode(newNode)) return void 0;
4476
+ this._attachNewNode(pred, "right", newNode);
4477
+ if (this._isMapMode) this._store.set(key, newNode);
4478
+ this._size++;
4479
+ const NIL = this.NIL;
4480
+ const hMin = this._header._left ?? NIL;
4481
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
4482
+ const hMax = this._header._right ?? NIL;
4483
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
4484
+ return newNode;
4485
+ }
4486
+ return this._setKVNode(key, value)?.node;
4487
+ }
4488
+ if (!this.isRealNode(hint.right)) {
4489
+ const newNode = this.createNode(key, value);
4490
+ if (!this.isRealNode(newNode)) return void 0;
4491
+ this._attachNewNode(hint, "right", newNode);
4492
+ if (this._isMapMode) this._store.set(key, newNode);
4493
+ this._size++;
4494
+ const NIL = this.NIL;
4495
+ const hMin = this._header._left ?? NIL;
4496
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
4497
+ const hMax = this._header._right ?? NIL;
4498
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
4499
+ return newNode;
4500
+ }
4501
+ const succ = this._successorOf(hint);
4502
+ if (succ && cmp(succ.key, key) <= 0) {
4503
+ return this._setKVNode(key, value)?.node;
4504
+ }
4505
+ if (succ && !this.isRealNode(succ.left)) {
4506
+ const newNode = this.createNode(key, value);
4507
+ if (!this.isRealNode(newNode)) return void 0;
4508
+ this._attachNewNode(succ, "left", newNode);
4509
+ if (this._isMapMode) this._store.set(key, newNode);
4510
+ this._size++;
4511
+ const NIL = this.NIL;
4512
+ const hMin = this._header._left ?? NIL;
4513
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
4514
+ const hMax = this._header._right ?? NIL;
4515
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
4516
+ return newNode;
4517
+ }
4518
+ return this._setKVNode(key, value)?.node;
4519
+ }
4520
+ /**
4521
+ * Boolean wrapper for setWithHintNode.
4522
+ * @remarks Time O(log n) average, Space O(1)
4523
+ */
4524
+ setWithHint(key, value, hint) {
4525
+ return this.setWithHintNode(key, value, hint) !== void 0;
4526
+ }
4527
+ /**
4528
+ * Insert or update a key/value (map mode) or key-only (set mode).
4529
+ *
4530
+ * This method is optimized for:
4531
+ * - monotonic inserts via min/max boundary fast paths
4532
+ * - updates via a single-pass search (no double walk)
4533
+ *
4534
+ * @remarks Time O(log n) average, Space O(1)
4112
4535
  */
4113
4536
  set(keyNodeOrEntry, value) {
4537
+ if (!this.isNode(keyNodeOrEntry)) {
4538
+ if (keyNodeOrEntry === null || keyNodeOrEntry === void 0) return false;
4539
+ if (this.isEntry(keyNodeOrEntry)) {
4540
+ const key = keyNodeOrEntry[0];
4541
+ if (key === null || key === void 0) return false;
4542
+ const nextValue = value ?? keyNodeOrEntry[1];
4543
+ return this._setKV(key, nextValue);
4544
+ }
4545
+ return this._setKV(keyNodeOrEntry, value);
4546
+ }
4114
4547
  const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
4115
4548
  if (!this.isRealNode(newNode)) return false;
4116
4549
  const insertStatus = this._insert(newNode);
@@ -4120,31 +4553,47 @@ var RedBlackTree = class extends BST {
4120
4553
  } else {
4121
4554
  return false;
4122
4555
  }
4123
- if (this._isMapMode) this._setValue(newNode.key, newValue);
4556
+ if (this._isMapMode) {
4557
+ const n = this.getNode(newNode.key);
4558
+ if (this.isRealNode(n)) {
4559
+ n.value = newValue;
4560
+ this._store.set(n.key, n);
4561
+ }
4562
+ }
4124
4563
  this._size++;
4125
4564
  return true;
4126
4565
  }
4127
4566
  if (insertStatus === "UPDATED") {
4128
- if (this._isMapMode) this._setValue(newNode.key, newValue);
4567
+ if (this._isMapMode) {
4568
+ const n = this.getNode(newNode.key);
4569
+ if (this.isRealNode(n)) {
4570
+ n.value = newValue;
4571
+ this._store.set(n.key, n);
4572
+ }
4573
+ }
4129
4574
  return true;
4130
4575
  }
4131
4576
  return false;
4132
4577
  }
4133
4578
  /**
4134
4579
  * Delete a node by key/node/entry and rebalance as needed.
4135
- * @remarks Time O(log n), Space O(1)
4136
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node to delete.
4580
+ * @remarks Time O(log n) average, Space O(1)
4581
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
4137
4582
  * @returns Array with deletion metadata (removed node, rebalancing hint if any).
4138
4583
  */
4139
- delete(keyNodeOrEntry) {
4140
- if (keyNodeOrEntry === null) return [];
4584
+ delete(keyNodeEntryRawOrPredicate) {
4585
+ if (keyNodeEntryRawOrPredicate === null) return [];
4141
4586
  const results = [];
4142
4587
  let nodeToDelete;
4143
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
4144
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
4588
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
4589
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
4145
4590
  if (!nodeToDelete) {
4146
4591
  return results;
4147
4592
  }
4593
+ const willDeleteMin = nodeToDelete === this._minNode;
4594
+ const willDeleteMax = nodeToDelete === this._maxNode;
4595
+ const nextMin = willDeleteMin ? this._successorOf(nodeToDelete) : void 0;
4596
+ const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : void 0;
4148
4597
  let originalColor = nodeToDelete.color;
4149
4598
  let replacementNode;
4150
4599
  if (!this.isRealNode(nodeToDelete.left)) {
@@ -4183,6 +4632,19 @@ var RedBlackTree = class extends BST {
4183
4632
  }
4184
4633
  if (this._isMapMode) this._store.delete(nodeToDelete.key);
4185
4634
  this._size--;
4635
+ if (this._size <= 0) {
4636
+ this._setMinCache(void 0);
4637
+ this._setMaxCache(void 0);
4638
+ } else {
4639
+ if (willDeleteMin) this._setMinCache(nextMin);
4640
+ if (willDeleteMax) this._setMaxCache(nextMax);
4641
+ if (!this._minNode || !this.isRealNode(this._minNode)) {
4642
+ this._setMinCache(this.isRealNode(this._root) ? this.getLeftMost((n) => n, this._root) : void 0);
4643
+ }
4644
+ if (!this._maxNode || !this.isRealNode(this._maxNode)) {
4645
+ this._setMaxCache(this.isRealNode(this._root) ? this.getRightMost((n) => n, this._root) : void 0);
4646
+ }
4647
+ }
4186
4648
  if (originalColor === "BLACK") {
4187
4649
  this._deleteFixup(replacementNode);
4188
4650
  }
@@ -4191,7 +4653,7 @@ var RedBlackTree = class extends BST {
4191
4653
  }
4192
4654
  /**
4193
4655
  * Transform entries into a like-kind red-black tree with possibly different key/value types.
4194
- * @remarks Time O(n), Space O(n)
4656
+ * @remarks Time O(n) average, Space O(n)
4195
4657
  * @template MK
4196
4658
  * @template MV
4197
4659
  * @template MR
@@ -4208,40 +4670,61 @@ var RedBlackTree = class extends BST {
4208
4670
  }
4209
4671
  return out;
4210
4672
  }
4673
+ /**
4674
+ * (Internal) Create an empty instance of the same concrete tree type.
4675
+ * @remarks Time O(1) average, Space O(1)
4676
+ */
4211
4677
  _createInstance(options) {
4212
4678
  const Ctor = this.constructor;
4213
4679
  return new Ctor([], { ...this._snapshotOptions(), ...options ?? {} });
4214
4680
  }
4681
+ /**
4682
+ * (Internal) Create a like-kind tree (same concrete class) populated from an iterable.
4683
+ * @remarks Time O(m log m) average (m = iterable length), Space O(m)
4684
+ */
4215
4685
  _createLike(iter = [], options) {
4216
4686
  const Ctor = this.constructor;
4217
4687
  return new Ctor(iter, { ...this._snapshotOptions(), ...options ?? {} });
4218
4688
  }
4689
+ /**
4690
+ * (Internal) Set the root pointer and keep header.parent in sync.
4691
+ * @remarks Time O(1), Space O(1)
4692
+ */
4219
4693
  _setRoot(v) {
4694
+ const NIL = this.NIL;
4220
4695
  if (v) {
4221
4696
  v.parent = void 0;
4222
4697
  }
4223
4698
  this._root = v;
4699
+ this._header.parent = v ?? NIL;
4224
4700
  }
4701
+ /**
4702
+ * (Internal) Replace a node in place while preserving its color.
4703
+ * @remarks Time O(1) average, Space O(1)
4704
+ */
4225
4705
  _replaceNode(oldNode, newNode) {
4226
4706
  newNode.color = oldNode.color;
4227
4707
  return super._replaceNode(oldNode, newNode);
4228
4708
  }
4229
4709
  /**
4230
4710
  * (Protected) Standard BST insert followed by red-black fix-up.
4231
- * @remarks Time O(log n), Space O(1)
4711
+ * @remarks Time O(log n) average, Space O(1)
4232
4712
  * @param node - Node to insert.
4233
4713
  * @returns Status string: 'CREATED' or 'UPDATED'.
4234
4714
  */
4235
4715
  _insert(node) {
4236
- let current = this.root ?? this.NIL;
4237
- let parent = void 0;
4238
- while (current !== this.NIL) {
4716
+ const NIL = this.NIL;
4717
+ const cmp = this._compare.bind(this);
4718
+ let current = this._header.parent ?? NIL;
4719
+ let parent;
4720
+ let lastCompared = 0;
4721
+ while (current !== NIL) {
4239
4722
  parent = current;
4240
- const compared = this._compare(node.key, current.key);
4241
- if (compared < 0) {
4242
- current = current.left ?? this.NIL;
4243
- } else if (compared > 0) {
4244
- current = current.right ?? this.NIL;
4723
+ lastCompared = cmp(node.key, current.key);
4724
+ if (lastCompared < 0) {
4725
+ current = current.left ?? NIL;
4726
+ } else if (lastCompared > 0) {
4727
+ current = current.right ?? NIL;
4245
4728
  } else {
4246
4729
  this._replaceNode(current, node);
4247
4730
  return "UPDATED";
@@ -4250,13 +4733,13 @@ var RedBlackTree = class extends BST {
4250
4733
  node.parent = parent;
4251
4734
  if (!parent) {
4252
4735
  this._setRoot(node);
4253
- } else if (this._compare(node.key, parent.key) < 0) {
4736
+ } else if (lastCompared < 0) {
4254
4737
  parent.left = node;
4255
4738
  } else {
4256
4739
  parent.right = node;
4257
4740
  }
4258
- node.left = this.NIL;
4259
- node.right = this.NIL;
4741
+ node.left = NIL;
4742
+ node.right = NIL;
4260
4743
  node.color = "RED";
4261
4744
  this._insertFixup(node);
4262
4745
  return "CREATED";
@@ -4282,55 +4765,66 @@ var RedBlackTree = class extends BST {
4282
4765
  }
4283
4766
  /**
4284
4767
  * (Protected) Restore red-black properties after insertion (recolor/rotate).
4285
- * @remarks Time O(log n), Space O(1)
4768
+ * @remarks Time O(log n) average, Space O(1)
4286
4769
  * @param z - Recently inserted node.
4287
4770
  * @returns void
4288
4771
  */
4289
4772
  _insertFixup(z) {
4290
- while (z?.parent?.color === "RED") {
4291
- if (z.parent === z.parent.parent?.left) {
4292
- const y = z.parent.parent.right;
4773
+ const leftRotate = this._leftRotate.bind(this);
4774
+ const rightRotate = this._rightRotate.bind(this);
4775
+ while (z) {
4776
+ const p = z.parent;
4777
+ if (!p || p.color !== "RED") break;
4778
+ const gp = p.parent;
4779
+ if (!gp) break;
4780
+ if (p === gp.left) {
4781
+ const y = gp.right;
4293
4782
  if (y?.color === "RED") {
4294
- z.parent.color = "BLACK";
4783
+ p.color = "BLACK";
4295
4784
  y.color = "BLACK";
4296
- z.parent.parent.color = "RED";
4297
- z = z.parent.parent;
4298
- } else {
4299
- if (z === z.parent.right) {
4300
- z = z.parent;
4301
- this._leftRotate(z);
4302
- }
4303
- if (z && z.parent && z.parent.parent) {
4304
- z.parent.color = "BLACK";
4305
- z.parent.parent.color = "RED";
4306
- this._rightRotate(z.parent.parent);
4307
- }
4785
+ gp.color = "RED";
4786
+ z = gp;
4787
+ continue;
4788
+ }
4789
+ if (z === p.right) {
4790
+ z = p;
4791
+ leftRotate(z);
4792
+ }
4793
+ const p2 = z?.parent;
4794
+ const gp2 = p2?.parent;
4795
+ if (p2 && gp2) {
4796
+ p2.color = "BLACK";
4797
+ gp2.color = "RED";
4798
+ rightRotate(gp2);
4308
4799
  }
4309
4800
  } else {
4310
- const y = z?.parent?.parent?.left ?? void 0;
4801
+ const y = gp.left;
4311
4802
  if (y?.color === "RED") {
4312
- z.parent.color = "BLACK";
4803
+ p.color = "BLACK";
4313
4804
  y.color = "BLACK";
4314
- z.parent.parent.color = "RED";
4315
- z = z.parent.parent;
4316
- } else {
4317
- if (z === z.parent.left) {
4318
- z = z.parent;
4319
- this._rightRotate(z);
4320
- }
4321
- if (z && z.parent && z.parent.parent) {
4322
- z.parent.color = "BLACK";
4323
- z.parent.parent.color = "RED";
4324
- this._leftRotate(z.parent.parent);
4325
- }
4805
+ gp.color = "RED";
4806
+ z = gp;
4807
+ continue;
4808
+ }
4809
+ if (z === p.left) {
4810
+ z = p;
4811
+ rightRotate(z);
4812
+ }
4813
+ const p2 = z?.parent;
4814
+ const gp2 = p2?.parent;
4815
+ if (p2 && gp2) {
4816
+ p2.color = "BLACK";
4817
+ gp2.color = "RED";
4818
+ leftRotate(gp2);
4326
4819
  }
4327
4820
  }
4821
+ break;
4328
4822
  }
4329
4823
  if (this.isRealNode(this._root)) this._root.color = "BLACK";
4330
4824
  }
4331
4825
  /**
4332
4826
  * (Protected) Restore red-black properties after deletion (recolor/rotate).
4333
- * @remarks Time O(log n), Space O(1)
4827
+ * @remarks Time O(log n) average, Space O(1)
4334
4828
  * @param node - Child that replaced the deleted node (may be undefined).
4335
4829
  * @returns void
4336
4830
  */