data-structure-typed 2.2.8 → 2.3.0

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 (137) hide show
  1. package/.github/workflows/ci.yml +9 -0
  2. package/CHANGELOG.md +1 -1
  3. package/README.md +1 -1
  4. package/README_CN.md +1 -1
  5. package/dist/cjs/index.cjs +584 -76
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs-legacy/index.cjs +588 -79
  8. package/dist/cjs-legacy/index.cjs.map +1 -1
  9. package/dist/esm/index.mjs +584 -76
  10. package/dist/esm/index.mjs.map +1 -1
  11. package/dist/esm-legacy/index.mjs +588 -79
  12. package/dist/esm-legacy/index.mjs.map +1 -1
  13. package/dist/types/data-structures/base/linear-base.d.ts +6 -6
  14. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +3 -4
  15. package/dist/types/data-structures/binary-tree/bst.d.ts +2 -1
  16. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +150 -20
  17. package/dist/types/data-structures/binary-tree/tree-counter.d.ts +3 -3
  18. package/dist/types/interfaces/binary-tree.d.ts +1 -1
  19. package/dist/umd/data-structure-typed.js +588 -79
  20. package/dist/umd/data-structure-typed.js.map +1 -1
  21. package/dist/umd/data-structure-typed.min.js +3 -3
  22. package/dist/umd/data-structure-typed.min.js.map +1 -1
  23. package/package.json +4 -3
  24. package/src/data-structures/base/linear-base.ts +2 -12
  25. package/src/data-structures/binary-tree/binary-tree.ts +5 -6
  26. package/src/data-structures/binary-tree/bst.ts +79 -4
  27. package/src/data-structures/binary-tree/red-black-tree.ts +583 -73
  28. package/src/data-structures/binary-tree/tree-counter.ts +21 -9
  29. package/src/data-structures/queue/deque.ts +10 -0
  30. package/src/interfaces/binary-tree.ts +1 -1
  31. package/test/unit/data-structures/base/iterable-element-base.coverage.test.ts +106 -0
  32. package/test/unit/data-structures/base/iterable-element-base.more-branches.coverage.test.ts +61 -0
  33. package/test/unit/data-structures/base/linear-base.array.coverage.test.ts +168 -0
  34. package/test/unit/data-structures/base/linear-base.concat-else.coverage.test.ts +82 -0
  35. package/test/unit/data-structures/base/linear-base.coverage.test.ts +72 -0
  36. package/test/unit/data-structures/base/linear-base.more-branches.coverage.test.ts +417 -0
  37. package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches-3.coverage.test.ts +146 -0
  38. package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches.coverage.test.ts +93 -0
  39. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.coverage.test.ts +108 -0
  40. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.more-branches-2.coverage.test.ts +85 -0
  41. package/test/unit/data-structures/binary-tree/avl-tree-node.familyPosition-root-left.coverage.test.ts +17 -0
  42. package/test/unit/data-structures/binary-tree/avl-tree.more-branches-2.coverage.test.ts +99 -0
  43. package/test/unit/data-structures/binary-tree/binary-indexed-tree.more-branches.coverage.test.ts +18 -0
  44. package/test/unit/data-structures/binary-tree/binary-tree.more-branches.coverage.test.ts +56 -0
  45. package/test/unit/data-structures/binary-tree/binary-tree.remaining-branches.coverage.test.ts +229 -0
  46. package/test/unit/data-structures/binary-tree/bst.bound-by-predicate.coverage.test.ts +33 -0
  47. package/test/unit/data-structures/binary-tree/bst.coverage.test.ts +94 -0
  48. package/test/unit/data-structures/binary-tree/bst.deletebykey.coverage.test.ts +70 -0
  49. package/test/unit/data-structures/binary-tree/bst.deletewhere.coverage.test.ts +37 -0
  50. package/test/unit/data-structures/binary-tree/bst.floor-lower-predicate.coverage.test.ts +29 -0
  51. package/test/unit/data-structures/binary-tree/bst.floor-setmany.coverage.test.ts +72 -0
  52. package/test/unit/data-structures/binary-tree/bst.getnode.range-ensure.coverage.test.ts +22 -0
  53. package/test/unit/data-structures/binary-tree/bst.misc-branches.coverage.test.ts +100 -0
  54. package/test/unit/data-structures/binary-tree/bst.more-branches-2.coverage.test.ts +133 -0
  55. package/test/unit/data-structures/binary-tree/bst.more-branches-3.coverage.test.ts +45 -0
  56. package/test/unit/data-structures/binary-tree/bst.more-branches-4.coverage.test.ts +36 -0
  57. package/test/unit/data-structures/binary-tree/bst.more-branches-5.coverage.test.ts +40 -0
  58. package/test/unit/data-structures/binary-tree/bst.more.coverage.test.ts +39 -0
  59. package/test/unit/data-structures/binary-tree/bst.node-family.coverage.test.ts +29 -0
  60. package/test/unit/data-structures/binary-tree/bst.range-pruning.coverage.test.ts +43 -0
  61. package/test/unit/data-structures/binary-tree/bst.search-fastpath.coverage.test.ts +30 -0
  62. package/test/unit/data-structures/binary-tree/bst.test.ts +25 -55
  63. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-corruption-repair.coverage.test.ts +66 -0
  64. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-max-update.coverage.test.ts +18 -0
  65. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-null.coverage.test.ts +53 -0
  66. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-stale-cache.coverage.test.ts +25 -0
  67. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-update.coverage.test.ts +23 -0
  68. package/test/unit/data-structures/binary-tree/red-black-tree.cache-delete.coverage.test.ts +49 -0
  69. package/test/unit/data-structures/binary-tree/red-black-tree.cache-edge.coverage.test.ts +37 -0
  70. package/test/unit/data-structures/binary-tree/red-black-tree.cache-stale-insert.coverage.test.ts +39 -0
  71. package/test/unit/data-structures/binary-tree/red-black-tree.coverage.test.ts +334 -0
  72. package/test/unit/data-structures/binary-tree/red-black-tree.delete-fixup.coverage.test.ts +68 -0
  73. package/test/unit/data-structures/binary-tree/red-black-tree.delete-successor.coverage.test.ts +75 -0
  74. package/test/unit/data-structures/binary-tree/red-black-tree.factories.coverage.test.ts +26 -0
  75. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-compare-update.coverage.test.ts +74 -0
  76. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-no-update.coverage.test.ts +44 -0
  77. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-nullish.coverage.test.ts +61 -0
  78. package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts +35 -0
  79. package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts +43 -0
  80. package/test/unit/data-structures/binary-tree/red-black-tree.hint-more.coverage.test.ts +99 -0
  81. package/test/unit/data-structures/binary-tree/red-black-tree.hint.coverage.test.ts +60 -0
  82. package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts +29 -0
  83. package/test/unit/data-structures/binary-tree/red-black-tree.insert-header-parent-nullish.coverage.test.ts +17 -0
  84. package/test/unit/data-structures/binary-tree/red-black-tree.internal-walk.coverage.test.ts +57 -0
  85. package/test/unit/data-structures/binary-tree/red-black-tree.minmax-cache.test.ts +65 -0
  86. package/test/unit/data-structures/binary-tree/red-black-tree.misc-inputs.coverage.test.ts +17 -0
  87. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-2.coverage.test.ts +121 -0
  88. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-3.coverage.test.ts +55 -0
  89. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-4.coverage.test.ts +44 -0
  90. package/test/unit/data-structures/binary-tree/red-black-tree.predsucc.coverage.test.ts +40 -0
  91. package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts +123 -0
  92. package/test/unit/data-structures/binary-tree/red-black-tree.set-inputs.coverage.test.ts +64 -0
  93. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts +79 -0
  94. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts +44 -0
  95. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts +74 -0
  96. package/test/unit/data-structures/binary-tree/red-black-tree.update-branches.coverage.test.ts +30 -0
  97. package/test/unit/data-structures/binary-tree/segment-tree.more-branches.coverage.test.ts +31 -0
  98. package/test/unit/data-structures/binary-tree/tree-counter.coverage.test.ts +115 -0
  99. package/test/unit/data-structures/binary-tree/tree-counter.more-branches.coverage.test.ts +244 -0
  100. package/test/unit/data-structures/binary-tree/tree-counter.test.ts +4 -2
  101. package/test/unit/data-structures/binary-tree/tree-multi-map.coverage.test.ts +104 -0
  102. package/test/unit/data-structures/binary-tree/tree-multi-map.more-branches-2.coverage.test.ts +59 -0
  103. package/test/unit/data-structures/graph/abstract-graph.more-branches-2.coverage.test.ts +40 -0
  104. package/test/unit/data-structures/graph/abstract-graph.more-branches-3.coverage.test.ts +65 -0
  105. package/test/unit/data-structures/graph/abstract-graph.more-branches-4.coverage.test.ts +98 -0
  106. package/test/unit/data-structures/graph/abstract-graph.more-branches-5.coverage.test.ts +51 -0
  107. package/test/unit/data-structures/graph/abstract-graph.more-branches.coverage.test.ts +62 -0
  108. package/test/unit/data-structures/graph/directed-graph.more-branches-2.coverage.test.ts +38 -0
  109. package/test/unit/data-structures/graph/directed-graph.more-branches-3.coverage.test.ts +25 -0
  110. package/test/unit/data-structures/graph/directed-graph.more-branches.coverage.test.ts +82 -0
  111. package/test/unit/data-structures/graph/map-graph.more-branches.coverage.test.ts +22 -0
  112. package/test/unit/data-structures/graph/undirected-graph.more-branches-2.coverage.test.ts +35 -0
  113. package/test/unit/data-structures/graph/undirected-graph.more-branches.coverage.test.ts +87 -0
  114. package/test/unit/data-structures/hash/hash-map.more-branches.coverage.test.ts +64 -0
  115. package/test/unit/data-structures/hash/hash-map.toEntryFn-branch.coverage.test.ts +9 -0
  116. package/test/unit/data-structures/heap/heap.misc-branches.coverage.test.ts +110 -0
  117. package/test/unit/data-structures/heap/heap.remaining-branches.coverage.test.ts +22 -0
  118. package/test/unit/data-structures/heap/max-heap.coverage.test.ts +29 -0
  119. package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts +72 -0
  120. package/test/unit/data-structures/linked-list/linked-list.unshiftMany-else.coverage.test.ts +15 -0
  121. package/test/unit/data-structures/linked-list/singly-linked-list.coverage.test.ts +221 -0
  122. package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts +86 -0
  123. package/test/unit/data-structures/linked-list/skip-linked-list.more-branches.coverage.test.ts +31 -0
  124. package/test/unit/data-structures/matrix/matrix.more-branches.coverage.test.ts +81 -0
  125. package/test/unit/data-structures/matrix/matrix.pivotElement-nullish.coverage.test.ts +28 -0
  126. package/test/unit/data-structures/priority-queue/max-priority-queue.more-branches.coverage.test.ts +10 -0
  127. package/test/unit/data-structures/priority-queue/priority-queue.coverage.test.ts +21 -0
  128. package/test/unit/data-structures/queue/deque.coverage.test.ts +173 -0
  129. package/test/unit/data-structures/queue/deque.more-branches-2.coverage.test.ts +39 -0
  130. package/test/unit/data-structures/queue/deque.more-branches-3.coverage.test.ts +9 -0
  131. package/test/unit/data-structures/queue/deque.more-branches.coverage.test.ts +95 -0
  132. package/test/unit/data-structures/queue/queue.coverage.test.ts +138 -0
  133. package/test/unit/data-structures/queue/queue.more-branches-2.coverage.test.ts +27 -0
  134. package/test/unit/data-structures/stack/stack.coverage.test.ts +112 -0
  135. package/test/unit/data-structures/tree/tree.more-branches.coverage.test.ts +9 -0
  136. package/test/unit/data-structures/trie/trie.more-branches-2.coverage.test.ts +51 -0
  137. package/test/utils/patch.ts +33 -0
@@ -1404,6 +1404,12 @@ var LinearLinkedBase = class extends LinearBase {
1404
1404
  }
1405
1405
  return -1;
1406
1406
  }
1407
+ /**
1408
+ * Concatenate lists/elements preserving order.
1409
+ * @param items - Elements or `LinearBase` instances.
1410
+ * @returns New list with combined elements (`this` type).
1411
+ * @remarks Time O(sum(length)), Space O(sum(length))
1412
+ */
1407
1413
  concat(...items) {
1408
1414
  const newList = this.clone();
1409
1415
  for (const item of items) {
@@ -4230,6 +4236,12 @@ var Deque = class extends LinearBase {
4230
4236
  */
4231
4237
  _setBucketSize(size) {
4232
4238
  this._bucketSize = size;
4239
+ if (this._length === 0) {
4240
+ this._buckets = [new Array(this._bucketSize)];
4241
+ this._bucketCount = 1;
4242
+ this._bucketFirst = this._bucketLast = 0;
4243
+ this._firstInBucket = this._lastInBucket = this._bucketSize >> 1;
4244
+ }
4233
4245
  }
4234
4246
  /**
4235
4247
  * (Protected) Iterate elements from front to back.
@@ -7285,7 +7297,6 @@ var BinaryTree = class extends IterableEntryBase {
7285
7297
  * @remarks Time O(N * M), where N is the number of items to set and M is the size of the tree at insertion (due to O(M) `set` operation). Space O(M) (from `set`) + O(N) (for the `inserted` array).
7286
7298
  *
7287
7299
  * @param keysNodesEntriesOrRaws - An iterable of items to set.
7288
- * @param [values] - An optional parallel iterable of values.
7289
7300
  * @returns An array of booleans indicating the success of each individual `set` operation.
7290
7301
  */
7291
7302
  addMany(keysNodesEntriesOrRaws) {
@@ -7342,13 +7353,13 @@ var BinaryTree = class extends IterableEntryBase {
7342
7353
  * Deletes a node from the tree.
7343
7354
  * @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).
7344
7355
  *
7345
- * @param keyNodeOrEntry - The node to delete.
7356
+ * @param keyNodeEntryRawOrPredicate - The node to delete.
7346
7357
  * @returns An array containing deletion results (for compatibility with self-balancing trees).
7347
7358
  */
7348
- delete(keyNodeOrEntry) {
7359
+ delete(keyNodeEntryRawOrPredicate) {
7349
7360
  const deletedResult = [];
7350
7361
  if (!this._root) return deletedResult;
7351
- const curr = this.getNode(keyNodeOrEntry);
7362
+ const curr = this.getNode(keyNodeEntryRawOrPredicate);
7352
7363
  if (!curr) return deletedResult;
7353
7364
  const parent = curr?.parent;
7354
7365
  let needBalanced;
@@ -7531,7 +7542,7 @@ var BinaryTree = class extends IterableEntryBase {
7531
7542
  }
7532
7543
  return true;
7533
7544
  }, "checkBST");
7534
- const isStandardBST = checkBST(false);
7545
+ const isStandardBST = checkBST();
7535
7546
  const isInverseBST = checkBST(true);
7536
7547
  return isStandardBST || isInverseBST;
7537
7548
  }
@@ -8769,7 +8780,39 @@ var BST = class extends BinaryTree {
8769
8780
  * @returns The first matching node, or undefined if not found.
8770
8781
  */
8771
8782
  getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
8772
- return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
8783
+ if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === void 0) return void 0;
8784
+ if (this._isPredicate(keyNodeEntryOrPredicate)) {
8785
+ return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
8786
+ }
8787
+ if (keyNodeEntryOrPredicate instanceof Range) {
8788
+ return this.getNodes(
8789
+ keyNodeEntryOrPredicate,
8790
+ true,
8791
+ startNode,
8792
+ iterationType
8793
+ )[0] ?? void 0;
8794
+ }
8795
+ let targetKey;
8796
+ if (this.isNode(keyNodeEntryOrPredicate)) {
8797
+ targetKey = keyNodeEntryOrPredicate.key;
8798
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
8799
+ const k = keyNodeEntryOrPredicate[0];
8800
+ if (k === null || k === void 0) return void 0;
8801
+ targetKey = k;
8802
+ } else {
8803
+ targetKey = keyNodeEntryOrPredicate;
8804
+ }
8805
+ const start = this.ensureNode(startNode);
8806
+ if (!start) return void 0;
8807
+ const NIL = this._NIL;
8808
+ let cur = start;
8809
+ const cmpFn = this._comparator;
8810
+ while (cur && cur !== NIL) {
8811
+ const c = cmpFn(targetKey, cur.key);
8812
+ if (c === 0) return cur;
8813
+ cur = c < 0 ? cur._left : cur._right;
8814
+ }
8815
+ return void 0;
8773
8816
  }
8774
8817
  /**
8775
8818
  * Searches the tree for nodes matching a predicate, key, or range.
@@ -8790,8 +8833,30 @@ var BST = class extends BinaryTree {
8790
8833
  if (keyNodeEntryOrPredicate === null) return [];
8791
8834
  startNode = this.ensureNode(startNode);
8792
8835
  if (!startNode) return [];
8793
- let predicate;
8794
8836
  const isRange = this.isRange(keyNodeEntryOrPredicate);
8837
+ const isPred = !isRange && this._isPredicate(keyNodeEntryOrPredicate);
8838
+ if (!isRange && !isPred) {
8839
+ let targetKey;
8840
+ if (this.isNode(keyNodeEntryOrPredicate)) {
8841
+ targetKey = keyNodeEntryOrPredicate.key;
8842
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
8843
+ const k = keyNodeEntryOrPredicate[0];
8844
+ if (k !== null && k !== void 0) targetKey = k;
8845
+ } else {
8846
+ targetKey = keyNodeEntryOrPredicate;
8847
+ }
8848
+ if (targetKey === void 0) return [];
8849
+ const NIL = this._NIL;
8850
+ const cmpFn = this._comparator;
8851
+ let cur = startNode;
8852
+ while (cur && cur !== NIL) {
8853
+ const c = cmpFn(targetKey, cur.key);
8854
+ if (c === 0) return [callback(cur)];
8855
+ cur = c < 0 ? cur._left : cur._right;
8856
+ }
8857
+ return [];
8858
+ }
8859
+ let predicate;
8795
8860
  if (isRange) {
8796
8861
  predicate = /* @__PURE__ */ __name((node) => {
8797
8862
  if (!node) return false;
@@ -9713,7 +9778,7 @@ var BST = class extends BinaryTree {
9713
9778
  succ.left = node.left;
9714
9779
  if (succ.left) succ.left.parent = succ;
9715
9780
  }
9716
- this._size = Math.max(0, (this._size ?? 0) - 1);
9781
+ this._size = Math.max(0, this._size - 1);
9717
9782
  return true;
9718
9783
  }
9719
9784
  };
@@ -10829,12 +10894,11 @@ var RedBlackTreeNode = class {
10829
10894
  value;
10830
10895
  parent = void 0;
10831
10896
  /**
10832
- * Create a Red-Black Tree and optionally bulk-insert items.
10833
- * @remarks Time O(n log n), Space O(n)
10834
- * @param key - See parameter type for details.
10835
- * @param [value]- See parameter type for details.
10836
- * @param color - See parameter type for details.
10837
- * @returns New RedBlackTree instance.
10897
+ * Create a Red-Black Tree node.
10898
+ * @remarks Time O(1), Space O(1)
10899
+ * @param key - Node key.
10900
+ * @param [value] - Node value (unused in map mode trees).
10901
+ * @param color - Node color.
10838
10902
  */
10839
10903
  constructor(key, value, color = "BLACK") {
10840
10904
  this.key = key;
@@ -10965,11 +11029,33 @@ var RedBlackTree = class extends BST {
10965
11029
  constructor(keysNodesEntriesOrRaws = [], options) {
10966
11030
  super([], options);
10967
11031
  this._root = this.NIL;
11032
+ this._header = new RedBlackTreeNode(void 0, void 0, "BLACK");
11033
+ this._header.parent = this.NIL;
11034
+ this._header._left = this.NIL;
11035
+ this._header._right = this.NIL;
10968
11036
  if (keysNodesEntriesOrRaws) {
10969
11037
  this.setMany(keysNodesEntriesOrRaws);
10970
11038
  }
10971
11039
  }
10972
11040
  _root;
11041
+ /**
11042
+ * (Internal) Header sentinel:
11043
+ * - header.parent -> root
11044
+ * - header._left -> min (or NIL)
11045
+ * - header._right -> max (or NIL)
11046
+ *
11047
+ * IMPORTANT:
11048
+ * - This header is NOT part of the actual tree.
11049
+ * - Do NOT use `header.left` / `header.right` accessors for wiring: those setters update `NIL.parent`
11050
+ * and can corrupt sentinel invariants / cause hangs. Only touch `header._left/_right`.
11051
+ */
11052
+ _header;
11053
+ /**
11054
+ * (Internal) Cache of the current minimum and maximum nodes.
11055
+ * Used for fast-path insert/update when keys are monotonic or near-boundary.
11056
+ */
11057
+ _minNode;
11058
+ _maxNode;
10973
11059
  /**
10974
11060
  * Get the current root node.
10975
11061
  * @remarks Time O(1), Space O(1)
@@ -11003,18 +11089,387 @@ var RedBlackTree = class extends BST {
11003
11089
  * @remarks Time O(n), Space O(1)
11004
11090
  * @returns void
11005
11091
  */
11092
+ /**
11093
+ * Remove all nodes and clear internal caches.
11094
+ * @remarks Time O(n) average, Space O(1)
11095
+ */
11006
11096
  clear() {
11007
11097
  super.clear();
11008
11098
  this._root = this.NIL;
11099
+ this._header.parent = this.NIL;
11100
+ this._setMinCache(void 0);
11101
+ this._setMaxCache(void 0);
11009
11102
  }
11010
11103
  /**
11011
- * Insert or replace an entry using BST order and red-black fix-up.
11012
- * @remarks Time O(log n), Space O(1)
11013
- * @param keyNodeOrEntry - Key, node, or [key, value] entry to insert.
11014
- * @param [value]- See parameter type for details.
11015
- * @returns True if inserted or updated; false if ignored.
11104
+ * (Internal) Find a node by key using a tight BST walk (no allocations).
11105
+ *
11106
+ * NOTE: This uses `header.parent` as the canonical root pointer.
11107
+ * @remarks Time O(log n) average, Space O(1)
11108
+ */
11109
+ _findNodeByKey(key) {
11110
+ const NIL = this.NIL;
11111
+ const cmp = this._compare.bind(this);
11112
+ let cur = this._header.parent ?? NIL;
11113
+ while (cur !== NIL) {
11114
+ const c = cmp(key, cur.key);
11115
+ if (c < 0) cur = cur.left ?? NIL;
11116
+ else if (c > 0) cur = cur.right ?? NIL;
11117
+ else return cur;
11118
+ }
11119
+ return void 0;
11120
+ }
11121
+ /**
11122
+ * (Internal) In-order predecessor of a node in a BST.
11123
+ * @remarks Time O(log n) average, Space O(1)
11124
+ */
11125
+ _predecessorOf(node) {
11126
+ const NIL = this.NIL;
11127
+ if (node.left && node.left !== NIL) {
11128
+ let cur2 = node.left;
11129
+ while (cur2.right && cur2.right !== NIL) cur2 = cur2.right;
11130
+ return cur2;
11131
+ }
11132
+ let cur = node;
11133
+ let p = node.parent;
11134
+ while (p && cur === p.left) {
11135
+ cur = p;
11136
+ p = p.parent;
11137
+ }
11138
+ return p;
11139
+ }
11140
+ /**
11141
+ * (Internal) In-order successor of a node in a BST.
11142
+ * @remarks Time O(log n) average, Space O(1)
11143
+ */
11144
+ _successorOf(node) {
11145
+ const NIL = this.NIL;
11146
+ if (node.right && node.right !== NIL) {
11147
+ let cur2 = node.right;
11148
+ while (cur2.left && cur2.left !== NIL) cur2 = cur2.left;
11149
+ return cur2;
11150
+ }
11151
+ let cur = node;
11152
+ let p = node.parent;
11153
+ while (p && cur === p.right) {
11154
+ cur = p;
11155
+ p = p.parent;
11156
+ }
11157
+ return p;
11158
+ }
11159
+ /**
11160
+ * (Internal) Attach a new node directly under a known parent/side (no search).
11161
+ *
11162
+ * This is a performance-oriented helper used by boundary fast paths and hinted insertion.
11163
+ * It will:
11164
+ * - wire parent/child pointers (using accessors, so parent pointers are updated)
11165
+ * - initialize children to NIL
11166
+ * - mark the new node RED, then run insert fix-up
11167
+ *
11168
+ * Precondition: the chosen slot (parent.left/parent.right) is empty (NIL/null/undefined).
11169
+ * @remarks Time O(log n) average, Space O(1)
11170
+ */
11171
+ _attachNewNode(parent, side, node) {
11172
+ const NIL = this.NIL;
11173
+ node.parent = parent;
11174
+ if (side === "left") parent.left = node;
11175
+ else parent.right = node;
11176
+ node.left = NIL;
11177
+ node.right = NIL;
11178
+ node.color = "RED";
11179
+ this._insertFixup(node);
11180
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
11181
+ }
11182
+ /**
11183
+ * (Internal) a single source of truth for min/max is header._left/_right.
11184
+ * Keep legacy _minNode/_maxNode mirrored for compatibility.
11185
+ * @remarks Time O(1), Space O(1)
11186
+ */
11187
+ /**
11188
+ * (Internal) Update min cache pointers (header._left is the canonical min pointer).
11189
+ * @remarks Time O(1), Space O(1)
11190
+ */
11191
+ _setMinCache(node) {
11192
+ this._minNode = node;
11193
+ this._header._left = node ?? this.NIL;
11194
+ }
11195
+ /**
11196
+ * (Internal) Update max cache pointers (header._right is the canonical max pointer).
11197
+ * @remarks Time O(1), Space O(1)
11198
+ */
11199
+ _setMaxCache(node) {
11200
+ this._maxNode = node;
11201
+ this._header._right = node ?? this.NIL;
11202
+ }
11203
+ /**
11204
+ * (Internal) Core set implementation returning the affected node.
11205
+ *
11206
+ * Hot path goals:
11207
+ * - Avoid double walks (search+insert): do a single traversal that either updates or inserts.
11208
+ * - Use header min/max caches to fast-path boundary inserts.
11209
+ * - Keep header._left/_right as canonical min/max pointers.
11210
+ *
11211
+ * Return value:
11212
+ * - `{ node, created:false }` when an existing key is updated
11213
+ * - `{ node, created:true }` when a new node is inserted
11214
+ * - `undefined` only on unexpected internal failure.
11215
+ * @remarks Time O(log n) average, Space O(1)
11216
+ */
11217
+ _setKVNode(key, nextValue) {
11218
+ const NIL = this.NIL;
11219
+ const comparator = this._comparator;
11220
+ const header = this._header;
11221
+ const minN = header._left ?? NIL;
11222
+ if (minN !== NIL) {
11223
+ const cMin = comparator(key, minN.key);
11224
+ if (cMin === 0) {
11225
+ if (this._isMapMode) {
11226
+ if (nextValue !== void 0) this._store.set(key, nextValue);
11227
+ else this._setValue(key, nextValue);
11228
+ } else minN.value = nextValue;
11229
+ return { node: minN, created: false };
11230
+ }
11231
+ const minL = minN.left;
11232
+ if (cMin < 0 && (minL === NIL || minL === null || minL === void 0)) {
11233
+ const newNode2 = this.createNode(key, nextValue);
11234
+ this._attachNewNode(minN, "left", newNode2);
11235
+ if (this._isMapMode) {
11236
+ if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
11237
+ else this._setValue(newNode2.key, nextValue);
11238
+ }
11239
+ this._size++;
11240
+ this._setMinCache(newNode2);
11241
+ if (header._right === NIL) this._setMaxCache(newNode2);
11242
+ return { node: newNode2, created: true };
11243
+ }
11244
+ if (cMin > 0) {
11245
+ const maxN = header._right ?? NIL;
11246
+ const cMax = comparator(key, maxN.key);
11247
+ if (cMax === 0) {
11248
+ if (this._isMapMode) {
11249
+ if (nextValue !== void 0) this._store.set(key, nextValue);
11250
+ else this._setValue(key, nextValue);
11251
+ } else maxN.value = nextValue;
11252
+ return { node: maxN, created: false };
11253
+ }
11254
+ const maxR = maxN.right;
11255
+ if (cMax > 0 && (maxR === NIL || maxR === null || maxR === void 0)) {
11256
+ const newNode2 = this.createNode(key, nextValue);
11257
+ this._attachNewNode(maxN, "right", newNode2);
11258
+ if (this._isMapMode) {
11259
+ if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
11260
+ else this._setValue(newNode2.key, nextValue);
11261
+ }
11262
+ this._size++;
11263
+ this._setMaxCache(newNode2);
11264
+ if (header._left === NIL) this._setMinCache(newNode2);
11265
+ return { node: newNode2, created: true };
11266
+ }
11267
+ }
11268
+ }
11269
+ const cmp = comparator;
11270
+ const isMapMode = this._isMapMode;
11271
+ const store = this._store;
11272
+ let current = this._header.parent ?? NIL;
11273
+ let parent;
11274
+ let lastCompared = 0;
11275
+ while (current !== NIL) {
11276
+ parent = current;
11277
+ lastCompared = cmp(key, current.key);
11278
+ if (lastCompared < 0) current = current.left ?? NIL;
11279
+ else if (lastCompared > 0) current = current.right ?? NIL;
11280
+ else {
11281
+ if (isMapMode) {
11282
+ if (nextValue !== void 0) store.set(key, nextValue);
11283
+ else this._setValue(key, nextValue);
11284
+ } else {
11285
+ current.value = nextValue;
11286
+ }
11287
+ return { node: current, created: false };
11288
+ }
11289
+ }
11290
+ const newNode = this.createNode(key, nextValue);
11291
+ newNode.parent = parent;
11292
+ if (!parent) {
11293
+ this._setRoot(newNode);
11294
+ } else if (lastCompared < 0) {
11295
+ parent.left = newNode;
11296
+ } else {
11297
+ parent.right = newNode;
11298
+ }
11299
+ newNode.left = NIL;
11300
+ newNode.right = NIL;
11301
+ newNode.color = "RED";
11302
+ this._insertFixup(newNode);
11303
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
11304
+ else return void 0;
11305
+ if (isMapMode) {
11306
+ if (nextValue !== void 0) store.set(newNode.key, nextValue);
11307
+ else this._setValue(newNode.key, nextValue);
11308
+ }
11309
+ this._size++;
11310
+ const hMin = this._header._left ?? NIL;
11311
+ const hMax = this._header._right ?? NIL;
11312
+ if (hMin === NIL || hMax === NIL) {
11313
+ this._setMinCache(newNode);
11314
+ this._setMaxCache(newNode);
11315
+ } else if (parent === hMax && lastCompared > 0) {
11316
+ this._setMaxCache(newNode);
11317
+ } else if (parent === hMin && lastCompared < 0) {
11318
+ this._setMinCache(newNode);
11319
+ } else {
11320
+ if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11321
+ if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11322
+ }
11323
+ return { node: newNode, created: true };
11324
+ }
11325
+ /**
11326
+ * (Internal) Boolean wrapper around `_setKVNode`.
11327
+ *
11328
+ * Includes a map-mode update fast-path:
11329
+ * - If `isMapMode=true` and the key already exists in `_store`, then updating the value does not
11330
+ * require any tree search/rotation (tree shape depends only on key).
11331
+ * - This path is intentionally limited to `nextValue !== undefined` to preserve existing
11332
+ * semantics for `undefined` values.
11333
+ * @remarks Time O(log n) average, Space O(1)
11334
+ */
11335
+ _setKV(key, nextValue) {
11336
+ if (this._isMapMode && nextValue !== void 0) {
11337
+ const store = this._store;
11338
+ if (store.has(key)) {
11339
+ store.set(key, nextValue);
11340
+ return true;
11341
+ }
11342
+ }
11343
+ return this._setKVNode(key, nextValue) !== void 0;
11344
+ }
11345
+ /**
11346
+ * Insert/update using a hint node to speed up nearby insertions.
11347
+ *
11348
+ * close to the expected insertion position (often the previously returned node in a loop).
11349
+ *
11350
+ * When the hint is a good fit (sorted / nearly-sorted insertion), this can avoid most of the
11351
+ * normal root-to-leaf search and reduce constant factors.
11352
+ *
11353
+ * When the hint does not match (random workloads), this will fall back to the normal set path.
11354
+ * @remarks Time O(log n) average, Space O(1)
11355
+ */
11356
+ setWithHintNode(key, value, hint) {
11357
+ if (!hint || !this.isRealNode(hint)) {
11358
+ return this._setKVNode(key, value)?.node;
11359
+ }
11360
+ const cmp = this._compare.bind(this);
11361
+ const c0 = cmp(key, hint.key);
11362
+ if (c0 === 0) {
11363
+ if (this._isMapMode) {
11364
+ if (value !== void 0) this._store.set(key, value);
11365
+ else this._setValue(key, value);
11366
+ } else hint.value = value;
11367
+ return hint;
11368
+ }
11369
+ if (c0 < 0) {
11370
+ if (!this.isRealNode(hint.left)) {
11371
+ const newNode = this.createNode(key, value);
11372
+ if (!this.isRealNode(newNode)) return void 0;
11373
+ this._attachNewNode(hint, "left", newNode);
11374
+ if (this._isMapMode) {
11375
+ if (value !== void 0) this._store.set(key, value);
11376
+ else this._setValue(key, value);
11377
+ }
11378
+ this._size++;
11379
+ const NIL = this.NIL;
11380
+ const hMin = this._header._left ?? NIL;
11381
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11382
+ const hMax = this._header._right ?? NIL;
11383
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11384
+ return newNode;
11385
+ }
11386
+ const pred = this._predecessorOf(hint);
11387
+ if (pred && cmp(pred.key, key) >= 0) {
11388
+ return this._setKVNode(key, value)?.node;
11389
+ }
11390
+ if (pred && !this.isRealNode(pred.right)) {
11391
+ const newNode = this.createNode(key, value);
11392
+ if (!this.isRealNode(newNode)) return void 0;
11393
+ this._attachNewNode(pred, "right", newNode);
11394
+ if (this._isMapMode) {
11395
+ if (value !== void 0) this._store.set(key, value);
11396
+ else this._setValue(key, value);
11397
+ }
11398
+ this._size++;
11399
+ const NIL = this.NIL;
11400
+ const hMin = this._header._left ?? NIL;
11401
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11402
+ const hMax = this._header._right ?? NIL;
11403
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11404
+ return newNode;
11405
+ }
11406
+ return this._setKVNode(key, value)?.node;
11407
+ }
11408
+ if (!this.isRealNode(hint.right)) {
11409
+ const newNode = this.createNode(key, value);
11410
+ if (!this.isRealNode(newNode)) return void 0;
11411
+ this._attachNewNode(hint, "right", newNode);
11412
+ if (this._isMapMode) {
11413
+ if (value !== void 0) this._store.set(key, value);
11414
+ else this._setValue(key, value);
11415
+ }
11416
+ this._size++;
11417
+ const NIL = this.NIL;
11418
+ const hMin = this._header._left ?? NIL;
11419
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11420
+ const hMax = this._header._right ?? NIL;
11421
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11422
+ return newNode;
11423
+ }
11424
+ const succ = this._successorOf(hint);
11425
+ if (succ && cmp(succ.key, key) <= 0) {
11426
+ return this._setKVNode(key, value)?.node;
11427
+ }
11428
+ if (succ && !this.isRealNode(succ.left)) {
11429
+ const newNode = this.createNode(key, value);
11430
+ if (!this.isRealNode(newNode)) return void 0;
11431
+ this._attachNewNode(succ, "left", newNode);
11432
+ if (this._isMapMode) {
11433
+ if (value !== void 0) this._store.set(key, value);
11434
+ else this._setValue(key, value);
11435
+ }
11436
+ this._size++;
11437
+ const NIL = this.NIL;
11438
+ const hMin = this._header._left ?? NIL;
11439
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11440
+ const hMax = this._header._right ?? NIL;
11441
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11442
+ return newNode;
11443
+ }
11444
+ return this._setKVNode(key, value)?.node;
11445
+ }
11446
+ /**
11447
+ * Boolean wrapper for setWithHintNode.
11448
+ * @remarks Time O(log n) average, Space O(1)
11449
+ */
11450
+ setWithHint(key, value, hint) {
11451
+ return this.setWithHintNode(key, value, hint) !== void 0;
11452
+ }
11453
+ /**
11454
+ * Insert or update a key/value (map mode) or key-only (set mode).
11455
+ *
11456
+ * This method is optimized for:
11457
+ * - monotonic inserts via min/max boundary fast paths
11458
+ * - updates via a single-pass search (no double walk)
11459
+ *
11460
+ * @remarks Time O(log n) average, Space O(1)
11016
11461
  */
11017
11462
  set(keyNodeOrEntry, value) {
11463
+ if (!this.isNode(keyNodeOrEntry)) {
11464
+ if (keyNodeOrEntry === null || keyNodeOrEntry === void 0) return false;
11465
+ if (this.isEntry(keyNodeOrEntry)) {
11466
+ const key = keyNodeOrEntry[0];
11467
+ if (key === null || key === void 0) return false;
11468
+ const nextValue = value ?? keyNodeOrEntry[1];
11469
+ return this._setKV(key, nextValue);
11470
+ }
11471
+ return this._setKV(keyNodeOrEntry, value);
11472
+ }
11018
11473
  const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
11019
11474
  if (!this.isRealNode(newNode)) return false;
11020
11475
  const insertStatus = this._insert(newNode);
@@ -11036,19 +11491,23 @@ var RedBlackTree = class extends BST {
11036
11491
  }
11037
11492
  /**
11038
11493
  * Delete a node by key/node/entry and rebalance as needed.
11039
- * @remarks Time O(log n), Space O(1)
11040
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node to delete.
11494
+ * @remarks Time O(log n) average, Space O(1)
11495
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
11041
11496
  * @returns Array with deletion metadata (removed node, rebalancing hint if any).
11042
11497
  */
11043
- delete(keyNodeOrEntry) {
11044
- if (keyNodeOrEntry === null) return [];
11498
+ delete(keyNodeEntryRawOrPredicate) {
11499
+ if (keyNodeEntryRawOrPredicate === null) return [];
11045
11500
  const results = [];
11046
11501
  let nodeToDelete;
11047
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
11048
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
11502
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
11503
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
11049
11504
  if (!nodeToDelete) {
11050
11505
  return results;
11051
11506
  }
11507
+ const willDeleteMin = nodeToDelete === this._minNode;
11508
+ const willDeleteMax = nodeToDelete === this._maxNode;
11509
+ const nextMin = willDeleteMin ? this._successorOf(nodeToDelete) : void 0;
11510
+ const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : void 0;
11052
11511
  let originalColor = nodeToDelete.color;
11053
11512
  let replacementNode;
11054
11513
  if (!this.isRealNode(nodeToDelete.left)) {
@@ -11087,6 +11546,19 @@ var RedBlackTree = class extends BST {
11087
11546
  }
11088
11547
  if (this._isMapMode) this._store.delete(nodeToDelete.key);
11089
11548
  this._size--;
11549
+ if (this._size <= 0) {
11550
+ this._setMinCache(void 0);
11551
+ this._setMaxCache(void 0);
11552
+ } else {
11553
+ if (willDeleteMin) this._setMinCache(nextMin);
11554
+ if (willDeleteMax) this._setMaxCache(nextMax);
11555
+ if (!this._minNode || !this.isRealNode(this._minNode)) {
11556
+ this._setMinCache(this.isRealNode(this._root) ? this.getLeftMost((n) => n, this._root) : void 0);
11557
+ }
11558
+ if (!this._maxNode || !this.isRealNode(this._maxNode)) {
11559
+ this._setMaxCache(this.isRealNode(this._root) ? this.getRightMost((n) => n, this._root) : void 0);
11560
+ }
11561
+ }
11090
11562
  if (originalColor === "BLACK") {
11091
11563
  this._deleteFixup(replacementNode);
11092
11564
  }
@@ -11095,7 +11567,7 @@ var RedBlackTree = class extends BST {
11095
11567
  }
11096
11568
  /**
11097
11569
  * Transform entries into a like-kind red-black tree with possibly different key/value types.
11098
- * @remarks Time O(n), Space O(n)
11570
+ * @remarks Time O(n) average, Space O(n)
11099
11571
  * @template MK
11100
11572
  * @template MV
11101
11573
  * @template MR
@@ -11112,40 +11584,61 @@ var RedBlackTree = class extends BST {
11112
11584
  }
11113
11585
  return out;
11114
11586
  }
11587
+ /**
11588
+ * (Internal) Create an empty instance of the same concrete tree type.
11589
+ * @remarks Time O(1) average, Space O(1)
11590
+ */
11115
11591
  _createInstance(options) {
11116
11592
  const Ctor = this.constructor;
11117
11593
  return new Ctor([], { ...this._snapshotOptions(), ...options ?? {} });
11118
11594
  }
11595
+ /**
11596
+ * (Internal) Create a like-kind tree (same concrete class) populated from an iterable.
11597
+ * @remarks Time O(m log m) average (m = iterable length), Space O(m)
11598
+ */
11119
11599
  _createLike(iter = [], options) {
11120
11600
  const Ctor = this.constructor;
11121
11601
  return new Ctor(iter, { ...this._snapshotOptions(), ...options ?? {} });
11122
11602
  }
11603
+ /**
11604
+ * (Internal) Set the root pointer and keep header.parent in sync.
11605
+ * @remarks Time O(1), Space O(1)
11606
+ */
11123
11607
  _setRoot(v) {
11608
+ const NIL = this.NIL;
11124
11609
  if (v) {
11125
11610
  v.parent = void 0;
11126
11611
  }
11127
11612
  this._root = v;
11613
+ this._header.parent = v ?? NIL;
11128
11614
  }
11615
+ /**
11616
+ * (Internal) Replace a node in place while preserving its color.
11617
+ * @remarks Time O(1) average, Space O(1)
11618
+ */
11129
11619
  _replaceNode(oldNode, newNode) {
11130
11620
  newNode.color = oldNode.color;
11131
11621
  return super._replaceNode(oldNode, newNode);
11132
11622
  }
11133
11623
  /**
11134
11624
  * (Protected) Standard BST insert followed by red-black fix-up.
11135
- * @remarks Time O(log n), Space O(1)
11625
+ * @remarks Time O(log n) average, Space O(1)
11136
11626
  * @param node - Node to insert.
11137
11627
  * @returns Status string: 'CREATED' or 'UPDATED'.
11138
11628
  */
11139
11629
  _insert(node) {
11140
- let current = this.root ?? this.NIL;
11141
- let parent = void 0;
11142
- while (current !== this.NIL) {
11630
+ const NIL = this.NIL;
11631
+ const cmp = this._compare.bind(this);
11632
+ let current = this._header.parent ?? NIL;
11633
+ let parent;
11634
+ let lastCompared = 0;
11635
+ while (current !== NIL) {
11143
11636
  parent = current;
11144
- const compared = this._compare(node.key, current.key);
11145
- if (compared < 0) {
11146
- current = current.left ?? this.NIL;
11147
- } else if (compared > 0) {
11148
- current = current.right ?? this.NIL;
11637
+ lastCompared = cmp(node.key, current.key);
11638
+ if (lastCompared < 0) {
11639
+ current = current.left ?? NIL;
11640
+ } else if (lastCompared > 0) {
11641
+ current = current.right ?? NIL;
11149
11642
  } else {
11150
11643
  this._replaceNode(current, node);
11151
11644
  return "UPDATED";
@@ -11154,13 +11647,13 @@ var RedBlackTree = class extends BST {
11154
11647
  node.parent = parent;
11155
11648
  if (!parent) {
11156
11649
  this._setRoot(node);
11157
- } else if (this._compare(node.key, parent.key) < 0) {
11650
+ } else if (lastCompared < 0) {
11158
11651
  parent.left = node;
11159
11652
  } else {
11160
11653
  parent.right = node;
11161
11654
  }
11162
- node.left = this.NIL;
11163
- node.right = this.NIL;
11655
+ node.left = NIL;
11656
+ node.right = NIL;
11164
11657
  node.color = "RED";
11165
11658
  this._insertFixup(node);
11166
11659
  return "CREATED";
@@ -11186,55 +11679,66 @@ var RedBlackTree = class extends BST {
11186
11679
  }
11187
11680
  /**
11188
11681
  * (Protected) Restore red-black properties after insertion (recolor/rotate).
11189
- * @remarks Time O(log n), Space O(1)
11682
+ * @remarks Time O(log n) average, Space O(1)
11190
11683
  * @param z - Recently inserted node.
11191
11684
  * @returns void
11192
11685
  */
11193
11686
  _insertFixup(z) {
11194
- while (z?.parent?.color === "RED") {
11195
- if (z.parent === z.parent.parent?.left) {
11196
- const y = z.parent.parent.right;
11687
+ const leftRotate = this._leftRotate.bind(this);
11688
+ const rightRotate = this._rightRotate.bind(this);
11689
+ while (z) {
11690
+ const p = z.parent;
11691
+ if (!p || p.color !== "RED") break;
11692
+ const gp = p.parent;
11693
+ if (!gp) break;
11694
+ if (p === gp.left) {
11695
+ const y = gp.right;
11197
11696
  if (y?.color === "RED") {
11198
- z.parent.color = "BLACK";
11697
+ p.color = "BLACK";
11199
11698
  y.color = "BLACK";
11200
- z.parent.parent.color = "RED";
11201
- z = z.parent.parent;
11202
- } else {
11203
- if (z === z.parent.right) {
11204
- z = z.parent;
11205
- this._leftRotate(z);
11206
- }
11207
- if (z && z.parent && z.parent.parent) {
11208
- z.parent.color = "BLACK";
11209
- z.parent.parent.color = "RED";
11210
- this._rightRotate(z.parent.parent);
11211
- }
11699
+ gp.color = "RED";
11700
+ z = gp;
11701
+ continue;
11702
+ }
11703
+ if (z === p.right) {
11704
+ z = p;
11705
+ leftRotate(z);
11706
+ }
11707
+ const p2 = z?.parent;
11708
+ const gp2 = p2?.parent;
11709
+ if (p2 && gp2) {
11710
+ p2.color = "BLACK";
11711
+ gp2.color = "RED";
11712
+ rightRotate(gp2);
11212
11713
  }
11213
11714
  } else {
11214
- const y = z?.parent?.parent?.left ?? void 0;
11715
+ const y = gp.left;
11215
11716
  if (y?.color === "RED") {
11216
- z.parent.color = "BLACK";
11717
+ p.color = "BLACK";
11217
11718
  y.color = "BLACK";
11218
- z.parent.parent.color = "RED";
11219
- z = z.parent.parent;
11220
- } else {
11221
- if (z === z.parent.left) {
11222
- z = z.parent;
11223
- this._rightRotate(z);
11224
- }
11225
- if (z && z.parent && z.parent.parent) {
11226
- z.parent.color = "BLACK";
11227
- z.parent.parent.color = "RED";
11228
- this._leftRotate(z.parent.parent);
11229
- }
11719
+ gp.color = "RED";
11720
+ z = gp;
11721
+ continue;
11722
+ }
11723
+ if (z === p.left) {
11724
+ z = p;
11725
+ rightRotate(z);
11726
+ }
11727
+ const p2 = z?.parent;
11728
+ const gp2 = p2?.parent;
11729
+ if (p2 && gp2) {
11730
+ p2.color = "BLACK";
11731
+ gp2.color = "RED";
11732
+ leftRotate(gp2);
11230
11733
  }
11231
11734
  }
11735
+ break;
11232
11736
  }
11233
11737
  if (this.isRealNode(this._root)) this._root.color = "BLACK";
11234
11738
  }
11235
11739
  /**
11236
11740
  * (Protected) Restore red-black properties after deletion (recolor/rotate).
11237
- * @remarks Time O(log n), Space O(1)
11741
+ * @remarks Time O(log n) average, Space O(1)
11238
11742
  * @param node - Child that replaced the deleted node (may be undefined).
11239
11743
  * @returns void
11240
11744
  */
@@ -12138,16 +12642,16 @@ var TreeCounter = class extends RedBlackTree {
12138
12642
  /**
12139
12643
  * Delete a node (or decrement its count) and rebalance if needed.
12140
12644
  * @remarks Time O(log N), Space O(1)
12141
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node.
12645
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node.
12142
12646
  * @param [ignoreCount] - If true, remove the node regardless of its count.
12143
12647
  * @returns Array of deletion results including deleted node and a rebalance hint when present.
12144
12648
  */
12145
- delete(keyNodeOrEntry, ignoreCount = false) {
12146
- if (keyNodeOrEntry === null) return [];
12649
+ delete(keyNodeEntryRawOrPredicate, ignoreCount = false) {
12650
+ if (keyNodeEntryRawOrPredicate === null) return [];
12147
12651
  const results = [];
12148
12652
  let nodeToDelete;
12149
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
12150
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
12653
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
12654
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
12151
12655
  if (!nodeToDelete) {
12152
12656
  return results;
12153
12657
  }
@@ -12190,7 +12694,6 @@ var TreeCounter = class extends RedBlackTree {
12190
12694
  if (ignoreCount || nodeToDelete.count <= 1) {
12191
12695
  if (successor.right !== null) {
12192
12696
  this._transplant(successor, successor.right);
12193
- this._count -= nodeToDelete.count;
12194
12697
  }
12195
12698
  } else {
12196
12699
  nodeToDelete.count--;
@@ -12293,6 +12796,11 @@ var TreeCounter = class extends RedBlackTree {
12293
12796
  const out = this._createInstance();
12294
12797
  this._clone(out);
12295
12798
  out._count = this._count;
12799
+ for (const node of this.dfs((n) => n, "IN")) {
12800
+ if (!node) continue;
12801
+ const outNode = out.getNode(node.key);
12802
+ if (outNode) outNode.count = node.count;
12803
+ }
12296
12804
  return out;
12297
12805
  }
12298
12806
  /**