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
@@ -1402,6 +1402,12 @@ var LinearLinkedBase = class extends LinearBase {
1402
1402
  }
1403
1403
  return -1;
1404
1404
  }
1405
+ /**
1406
+ * Concatenate lists/elements preserving order.
1407
+ * @param items - Elements or `LinearBase` instances.
1408
+ * @returns New list with combined elements (`this` type).
1409
+ * @remarks Time O(sum(length)), Space O(sum(length))
1410
+ */
1405
1411
  concat(...items) {
1406
1412
  const newList = this.clone();
1407
1413
  for (const item of items) {
@@ -4228,6 +4234,12 @@ var Deque = class extends LinearBase {
4228
4234
  */
4229
4235
  _setBucketSize(size) {
4230
4236
  this._bucketSize = size;
4237
+ if (this._length === 0) {
4238
+ this._buckets = [new Array(this._bucketSize)];
4239
+ this._bucketCount = 1;
4240
+ this._bucketFirst = this._bucketLast = 0;
4241
+ this._firstInBucket = this._lastInBucket = this._bucketSize >> 1;
4242
+ }
4231
4243
  }
4232
4244
  /**
4233
4245
  * (Protected) Iterate elements from front to back.
@@ -7283,7 +7295,6 @@ var BinaryTree = class extends IterableEntryBase {
7283
7295
  * @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).
7284
7296
  *
7285
7297
  * @param keysNodesEntriesOrRaws - An iterable of items to set.
7286
- * @param [values] - An optional parallel iterable of values.
7287
7298
  * @returns An array of booleans indicating the success of each individual `set` operation.
7288
7299
  */
7289
7300
  addMany(keysNodesEntriesOrRaws) {
@@ -7340,13 +7351,13 @@ var BinaryTree = class extends IterableEntryBase {
7340
7351
  * Deletes a node from the tree.
7341
7352
  * @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).
7342
7353
  *
7343
- * @param keyNodeOrEntry - The node to delete.
7354
+ * @param keyNodeEntryRawOrPredicate - The node to delete.
7344
7355
  * @returns An array containing deletion results (for compatibility with self-balancing trees).
7345
7356
  */
7346
- delete(keyNodeOrEntry) {
7357
+ delete(keyNodeEntryRawOrPredicate) {
7347
7358
  const deletedResult = [];
7348
7359
  if (!this._root) return deletedResult;
7349
- const curr = this.getNode(keyNodeOrEntry);
7360
+ const curr = this.getNode(keyNodeEntryRawOrPredicate);
7350
7361
  if (!curr) return deletedResult;
7351
7362
  const parent = curr?.parent;
7352
7363
  let needBalanced;
@@ -7529,7 +7540,7 @@ var BinaryTree = class extends IterableEntryBase {
7529
7540
  }
7530
7541
  return true;
7531
7542
  }, "checkBST");
7532
- const isStandardBST = checkBST(false);
7543
+ const isStandardBST = checkBST();
7533
7544
  const isInverseBST = checkBST(true);
7534
7545
  return isStandardBST || isInverseBST;
7535
7546
  }
@@ -8767,7 +8778,39 @@ var BST = class extends BinaryTree {
8767
8778
  * @returns The first matching node, or undefined if not found.
8768
8779
  */
8769
8780
  getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
8770
- return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
8781
+ if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === void 0) return void 0;
8782
+ if (this._isPredicate(keyNodeEntryOrPredicate)) {
8783
+ return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
8784
+ }
8785
+ if (keyNodeEntryOrPredicate instanceof Range) {
8786
+ return this.getNodes(
8787
+ keyNodeEntryOrPredicate,
8788
+ true,
8789
+ startNode,
8790
+ iterationType
8791
+ )[0] ?? void 0;
8792
+ }
8793
+ let targetKey;
8794
+ if (this.isNode(keyNodeEntryOrPredicate)) {
8795
+ targetKey = keyNodeEntryOrPredicate.key;
8796
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
8797
+ const k = keyNodeEntryOrPredicate[0];
8798
+ if (k === null || k === void 0) return void 0;
8799
+ targetKey = k;
8800
+ } else {
8801
+ targetKey = keyNodeEntryOrPredicate;
8802
+ }
8803
+ const start = this.ensureNode(startNode);
8804
+ if (!start) return void 0;
8805
+ const NIL = this._NIL;
8806
+ let cur = start;
8807
+ const cmpFn = this._comparator;
8808
+ while (cur && cur !== NIL) {
8809
+ const c = cmpFn(targetKey, cur.key);
8810
+ if (c === 0) return cur;
8811
+ cur = c < 0 ? cur._left : cur._right;
8812
+ }
8813
+ return void 0;
8771
8814
  }
8772
8815
  /**
8773
8816
  * Searches the tree for nodes matching a predicate, key, or range.
@@ -8788,8 +8831,30 @@ var BST = class extends BinaryTree {
8788
8831
  if (keyNodeEntryOrPredicate === null) return [];
8789
8832
  startNode = this.ensureNode(startNode);
8790
8833
  if (!startNode) return [];
8791
- let predicate;
8792
8834
  const isRange = this.isRange(keyNodeEntryOrPredicate);
8835
+ const isPred = !isRange && this._isPredicate(keyNodeEntryOrPredicate);
8836
+ if (!isRange && !isPred) {
8837
+ let targetKey;
8838
+ if (this.isNode(keyNodeEntryOrPredicate)) {
8839
+ targetKey = keyNodeEntryOrPredicate.key;
8840
+ } else if (this.isEntry(keyNodeEntryOrPredicate)) {
8841
+ const k = keyNodeEntryOrPredicate[0];
8842
+ if (k !== null && k !== void 0) targetKey = k;
8843
+ } else {
8844
+ targetKey = keyNodeEntryOrPredicate;
8845
+ }
8846
+ if (targetKey === void 0) return [];
8847
+ const NIL = this._NIL;
8848
+ const cmpFn = this._comparator;
8849
+ let cur = startNode;
8850
+ while (cur && cur !== NIL) {
8851
+ const c = cmpFn(targetKey, cur.key);
8852
+ if (c === 0) return [callback(cur)];
8853
+ cur = c < 0 ? cur._left : cur._right;
8854
+ }
8855
+ return [];
8856
+ }
8857
+ let predicate;
8793
8858
  if (isRange) {
8794
8859
  predicate = /* @__PURE__ */ __name((node) => {
8795
8860
  if (!node) return false;
@@ -9711,7 +9776,7 @@ var BST = class extends BinaryTree {
9711
9776
  succ.left = node.left;
9712
9777
  if (succ.left) succ.left.parent = succ;
9713
9778
  }
9714
- this._size = Math.max(0, (this._size ?? 0) - 1);
9779
+ this._size = Math.max(0, this._size - 1);
9715
9780
  return true;
9716
9781
  }
9717
9782
  };
@@ -10827,12 +10892,11 @@ var RedBlackTreeNode = class {
10827
10892
  value;
10828
10893
  parent = void 0;
10829
10894
  /**
10830
- * Create a Red-Black Tree and optionally bulk-insert items.
10831
- * @remarks Time O(n log n), Space O(n)
10832
- * @param key - See parameter type for details.
10833
- * @param [value]- See parameter type for details.
10834
- * @param color - See parameter type for details.
10835
- * @returns New RedBlackTree instance.
10895
+ * Create a Red-Black Tree node.
10896
+ * @remarks Time O(1), Space O(1)
10897
+ * @param key - Node key.
10898
+ * @param [value] - Node value (unused in map mode trees).
10899
+ * @param color - Node color.
10836
10900
  */
10837
10901
  constructor(key, value, color = "BLACK") {
10838
10902
  this.key = key;
@@ -10963,11 +11027,33 @@ var RedBlackTree = class extends BST {
10963
11027
  constructor(keysNodesEntriesOrRaws = [], options) {
10964
11028
  super([], options);
10965
11029
  this._root = this.NIL;
11030
+ this._header = new RedBlackTreeNode(void 0, void 0, "BLACK");
11031
+ this._header.parent = this.NIL;
11032
+ this._header._left = this.NIL;
11033
+ this._header._right = this.NIL;
10966
11034
  if (keysNodesEntriesOrRaws) {
10967
11035
  this.setMany(keysNodesEntriesOrRaws);
10968
11036
  }
10969
11037
  }
10970
11038
  _root;
11039
+ /**
11040
+ * (Internal) Header sentinel:
11041
+ * - header.parent -> root
11042
+ * - header._left -> min (or NIL)
11043
+ * - header._right -> max (or NIL)
11044
+ *
11045
+ * IMPORTANT:
11046
+ * - This header is NOT part of the actual tree.
11047
+ * - Do NOT use `header.left` / `header.right` accessors for wiring: those setters update `NIL.parent`
11048
+ * and can corrupt sentinel invariants / cause hangs. Only touch `header._left/_right`.
11049
+ */
11050
+ _header;
11051
+ /**
11052
+ * (Internal) Cache of the current minimum and maximum nodes.
11053
+ * Used for fast-path insert/update when keys are monotonic or near-boundary.
11054
+ */
11055
+ _minNode;
11056
+ _maxNode;
10971
11057
  /**
10972
11058
  * Get the current root node.
10973
11059
  * @remarks Time O(1), Space O(1)
@@ -11001,18 +11087,387 @@ var RedBlackTree = class extends BST {
11001
11087
  * @remarks Time O(n), Space O(1)
11002
11088
  * @returns void
11003
11089
  */
11090
+ /**
11091
+ * Remove all nodes and clear internal caches.
11092
+ * @remarks Time O(n) average, Space O(1)
11093
+ */
11004
11094
  clear() {
11005
11095
  super.clear();
11006
11096
  this._root = this.NIL;
11097
+ this._header.parent = this.NIL;
11098
+ this._setMinCache(void 0);
11099
+ this._setMaxCache(void 0);
11007
11100
  }
11008
11101
  /**
11009
- * Insert or replace an entry using BST order and red-black fix-up.
11010
- * @remarks Time O(log n), Space O(1)
11011
- * @param keyNodeOrEntry - Key, node, or [key, value] entry to insert.
11012
- * @param [value]- See parameter type for details.
11013
- * @returns True if inserted or updated; false if ignored.
11102
+ * (Internal) Find a node by key using a tight BST walk (no allocations).
11103
+ *
11104
+ * NOTE: This uses `header.parent` as the canonical root pointer.
11105
+ * @remarks Time O(log n) average, Space O(1)
11106
+ */
11107
+ _findNodeByKey(key) {
11108
+ const NIL = this.NIL;
11109
+ const cmp = this._compare.bind(this);
11110
+ let cur = this._header.parent ?? NIL;
11111
+ while (cur !== NIL) {
11112
+ const c = cmp(key, cur.key);
11113
+ if (c < 0) cur = cur.left ?? NIL;
11114
+ else if (c > 0) cur = cur.right ?? NIL;
11115
+ else return cur;
11116
+ }
11117
+ return void 0;
11118
+ }
11119
+ /**
11120
+ * (Internal) In-order predecessor of a node in a BST.
11121
+ * @remarks Time O(log n) average, Space O(1)
11122
+ */
11123
+ _predecessorOf(node) {
11124
+ const NIL = this.NIL;
11125
+ if (node.left && node.left !== NIL) {
11126
+ let cur2 = node.left;
11127
+ while (cur2.right && cur2.right !== NIL) cur2 = cur2.right;
11128
+ return cur2;
11129
+ }
11130
+ let cur = node;
11131
+ let p = node.parent;
11132
+ while (p && cur === p.left) {
11133
+ cur = p;
11134
+ p = p.parent;
11135
+ }
11136
+ return p;
11137
+ }
11138
+ /**
11139
+ * (Internal) In-order successor of a node in a BST.
11140
+ * @remarks Time O(log n) average, Space O(1)
11141
+ */
11142
+ _successorOf(node) {
11143
+ const NIL = this.NIL;
11144
+ if (node.right && node.right !== NIL) {
11145
+ let cur2 = node.right;
11146
+ while (cur2.left && cur2.left !== NIL) cur2 = cur2.left;
11147
+ return cur2;
11148
+ }
11149
+ let cur = node;
11150
+ let p = node.parent;
11151
+ while (p && cur === p.right) {
11152
+ cur = p;
11153
+ p = p.parent;
11154
+ }
11155
+ return p;
11156
+ }
11157
+ /**
11158
+ * (Internal) Attach a new node directly under a known parent/side (no search).
11159
+ *
11160
+ * This is a performance-oriented helper used by boundary fast paths and hinted insertion.
11161
+ * It will:
11162
+ * - wire parent/child pointers (using accessors, so parent pointers are updated)
11163
+ * - initialize children to NIL
11164
+ * - mark the new node RED, then run insert fix-up
11165
+ *
11166
+ * Precondition: the chosen slot (parent.left/parent.right) is empty (NIL/null/undefined).
11167
+ * @remarks Time O(log n) average, Space O(1)
11168
+ */
11169
+ _attachNewNode(parent, side, node) {
11170
+ const NIL = this.NIL;
11171
+ node.parent = parent;
11172
+ if (side === "left") parent.left = node;
11173
+ else parent.right = node;
11174
+ node.left = NIL;
11175
+ node.right = NIL;
11176
+ node.color = "RED";
11177
+ this._insertFixup(node);
11178
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
11179
+ }
11180
+ /**
11181
+ * (Internal) a single source of truth for min/max is header._left/_right.
11182
+ * Keep legacy _minNode/_maxNode mirrored for compatibility.
11183
+ * @remarks Time O(1), Space O(1)
11184
+ */
11185
+ /**
11186
+ * (Internal) Update min cache pointers (header._left is the canonical min pointer).
11187
+ * @remarks Time O(1), Space O(1)
11188
+ */
11189
+ _setMinCache(node) {
11190
+ this._minNode = node;
11191
+ this._header._left = node ?? this.NIL;
11192
+ }
11193
+ /**
11194
+ * (Internal) Update max cache pointers (header._right is the canonical max pointer).
11195
+ * @remarks Time O(1), Space O(1)
11196
+ */
11197
+ _setMaxCache(node) {
11198
+ this._maxNode = node;
11199
+ this._header._right = node ?? this.NIL;
11200
+ }
11201
+ /**
11202
+ * (Internal) Core set implementation returning the affected node.
11203
+ *
11204
+ * Hot path goals:
11205
+ * - Avoid double walks (search+insert): do a single traversal that either updates or inserts.
11206
+ * - Use header min/max caches to fast-path boundary inserts.
11207
+ * - Keep header._left/_right as canonical min/max pointers.
11208
+ *
11209
+ * Return value:
11210
+ * - `{ node, created:false }` when an existing key is updated
11211
+ * - `{ node, created:true }` when a new node is inserted
11212
+ * - `undefined` only on unexpected internal failure.
11213
+ * @remarks Time O(log n) average, Space O(1)
11214
+ */
11215
+ _setKVNode(key, nextValue) {
11216
+ const NIL = this.NIL;
11217
+ const comparator = this._comparator;
11218
+ const header = this._header;
11219
+ const minN = header._left ?? NIL;
11220
+ if (minN !== NIL) {
11221
+ const cMin = comparator(key, minN.key);
11222
+ if (cMin === 0) {
11223
+ if (this._isMapMode) {
11224
+ if (nextValue !== void 0) this._store.set(key, nextValue);
11225
+ else this._setValue(key, nextValue);
11226
+ } else minN.value = nextValue;
11227
+ return { node: minN, created: false };
11228
+ }
11229
+ const minL = minN.left;
11230
+ if (cMin < 0 && (minL === NIL || minL === null || minL === void 0)) {
11231
+ const newNode2 = this.createNode(key, nextValue);
11232
+ this._attachNewNode(minN, "left", newNode2);
11233
+ if (this._isMapMode) {
11234
+ if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
11235
+ else this._setValue(newNode2.key, nextValue);
11236
+ }
11237
+ this._size++;
11238
+ this._setMinCache(newNode2);
11239
+ if (header._right === NIL) this._setMaxCache(newNode2);
11240
+ return { node: newNode2, created: true };
11241
+ }
11242
+ if (cMin > 0) {
11243
+ const maxN = header._right ?? NIL;
11244
+ const cMax = comparator(key, maxN.key);
11245
+ if (cMax === 0) {
11246
+ if (this._isMapMode) {
11247
+ if (nextValue !== void 0) this._store.set(key, nextValue);
11248
+ else this._setValue(key, nextValue);
11249
+ } else maxN.value = nextValue;
11250
+ return { node: maxN, created: false };
11251
+ }
11252
+ const maxR = maxN.right;
11253
+ if (cMax > 0 && (maxR === NIL || maxR === null || maxR === void 0)) {
11254
+ const newNode2 = this.createNode(key, nextValue);
11255
+ this._attachNewNode(maxN, "right", newNode2);
11256
+ if (this._isMapMode) {
11257
+ if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
11258
+ else this._setValue(newNode2.key, nextValue);
11259
+ }
11260
+ this._size++;
11261
+ this._setMaxCache(newNode2);
11262
+ if (header._left === NIL) this._setMinCache(newNode2);
11263
+ return { node: newNode2, created: true };
11264
+ }
11265
+ }
11266
+ }
11267
+ const cmp = comparator;
11268
+ const isMapMode = this._isMapMode;
11269
+ const store = this._store;
11270
+ let current = this._header.parent ?? NIL;
11271
+ let parent;
11272
+ let lastCompared = 0;
11273
+ while (current !== NIL) {
11274
+ parent = current;
11275
+ lastCompared = cmp(key, current.key);
11276
+ if (lastCompared < 0) current = current.left ?? NIL;
11277
+ else if (lastCompared > 0) current = current.right ?? NIL;
11278
+ else {
11279
+ if (isMapMode) {
11280
+ if (nextValue !== void 0) store.set(key, nextValue);
11281
+ else this._setValue(key, nextValue);
11282
+ } else {
11283
+ current.value = nextValue;
11284
+ }
11285
+ return { node: current, created: false };
11286
+ }
11287
+ }
11288
+ const newNode = this.createNode(key, nextValue);
11289
+ newNode.parent = parent;
11290
+ if (!parent) {
11291
+ this._setRoot(newNode);
11292
+ } else if (lastCompared < 0) {
11293
+ parent.left = newNode;
11294
+ } else {
11295
+ parent.right = newNode;
11296
+ }
11297
+ newNode.left = NIL;
11298
+ newNode.right = NIL;
11299
+ newNode.color = "RED";
11300
+ this._insertFixup(newNode);
11301
+ if (this.isRealNode(this._root)) this._root.color = "BLACK";
11302
+ else return void 0;
11303
+ if (isMapMode) {
11304
+ if (nextValue !== void 0) store.set(newNode.key, nextValue);
11305
+ else this._setValue(newNode.key, nextValue);
11306
+ }
11307
+ this._size++;
11308
+ const hMin = this._header._left ?? NIL;
11309
+ const hMax = this._header._right ?? NIL;
11310
+ if (hMin === NIL || hMax === NIL) {
11311
+ this._setMinCache(newNode);
11312
+ this._setMaxCache(newNode);
11313
+ } else if (parent === hMax && lastCompared > 0) {
11314
+ this._setMaxCache(newNode);
11315
+ } else if (parent === hMin && lastCompared < 0) {
11316
+ this._setMinCache(newNode);
11317
+ } else {
11318
+ if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11319
+ if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11320
+ }
11321
+ return { node: newNode, created: true };
11322
+ }
11323
+ /**
11324
+ * (Internal) Boolean wrapper around `_setKVNode`.
11325
+ *
11326
+ * Includes a map-mode update fast-path:
11327
+ * - If `isMapMode=true` and the key already exists in `_store`, then updating the value does not
11328
+ * require any tree search/rotation (tree shape depends only on key).
11329
+ * - This path is intentionally limited to `nextValue !== undefined` to preserve existing
11330
+ * semantics for `undefined` values.
11331
+ * @remarks Time O(log n) average, Space O(1)
11332
+ */
11333
+ _setKV(key, nextValue) {
11334
+ if (this._isMapMode && nextValue !== void 0) {
11335
+ const store = this._store;
11336
+ if (store.has(key)) {
11337
+ store.set(key, nextValue);
11338
+ return true;
11339
+ }
11340
+ }
11341
+ return this._setKVNode(key, nextValue) !== void 0;
11342
+ }
11343
+ /**
11344
+ * Insert/update using a hint node to speed up nearby insertions.
11345
+ *
11346
+ * close to the expected insertion position (often the previously returned node in a loop).
11347
+ *
11348
+ * When the hint is a good fit (sorted / nearly-sorted insertion), this can avoid most of the
11349
+ * normal root-to-leaf search and reduce constant factors.
11350
+ *
11351
+ * When the hint does not match (random workloads), this will fall back to the normal set path.
11352
+ * @remarks Time O(log n) average, Space O(1)
11353
+ */
11354
+ setWithHintNode(key, value, hint) {
11355
+ if (!hint || !this.isRealNode(hint)) {
11356
+ return this._setKVNode(key, value)?.node;
11357
+ }
11358
+ const cmp = this._compare.bind(this);
11359
+ const c0 = cmp(key, hint.key);
11360
+ if (c0 === 0) {
11361
+ if (this._isMapMode) {
11362
+ if (value !== void 0) this._store.set(key, value);
11363
+ else this._setValue(key, value);
11364
+ } else hint.value = value;
11365
+ return hint;
11366
+ }
11367
+ if (c0 < 0) {
11368
+ if (!this.isRealNode(hint.left)) {
11369
+ const newNode = this.createNode(key, value);
11370
+ if (!this.isRealNode(newNode)) return void 0;
11371
+ this._attachNewNode(hint, "left", newNode);
11372
+ if (this._isMapMode) {
11373
+ if (value !== void 0) this._store.set(key, value);
11374
+ else this._setValue(key, value);
11375
+ }
11376
+ this._size++;
11377
+ const NIL = this.NIL;
11378
+ const hMin = this._header._left ?? NIL;
11379
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11380
+ const hMax = this._header._right ?? NIL;
11381
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11382
+ return newNode;
11383
+ }
11384
+ const pred = this._predecessorOf(hint);
11385
+ if (pred && cmp(pred.key, key) >= 0) {
11386
+ return this._setKVNode(key, value)?.node;
11387
+ }
11388
+ if (pred && !this.isRealNode(pred.right)) {
11389
+ const newNode = this.createNode(key, value);
11390
+ if (!this.isRealNode(newNode)) return void 0;
11391
+ this._attachNewNode(pred, "right", newNode);
11392
+ if (this._isMapMode) {
11393
+ if (value !== void 0) this._store.set(key, value);
11394
+ else this._setValue(key, value);
11395
+ }
11396
+ this._size++;
11397
+ const NIL = this.NIL;
11398
+ const hMin = this._header._left ?? NIL;
11399
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11400
+ const hMax = this._header._right ?? NIL;
11401
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11402
+ return newNode;
11403
+ }
11404
+ return this._setKVNode(key, value)?.node;
11405
+ }
11406
+ if (!this.isRealNode(hint.right)) {
11407
+ const newNode = this.createNode(key, value);
11408
+ if (!this.isRealNode(newNode)) return void 0;
11409
+ this._attachNewNode(hint, "right", newNode);
11410
+ if (this._isMapMode) {
11411
+ if (value !== void 0) this._store.set(key, value);
11412
+ else this._setValue(key, value);
11413
+ }
11414
+ this._size++;
11415
+ const NIL = this.NIL;
11416
+ const hMin = this._header._left ?? NIL;
11417
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11418
+ const hMax = this._header._right ?? NIL;
11419
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11420
+ return newNode;
11421
+ }
11422
+ const succ = this._successorOf(hint);
11423
+ if (succ && cmp(succ.key, key) <= 0) {
11424
+ return this._setKVNode(key, value)?.node;
11425
+ }
11426
+ if (succ && !this.isRealNode(succ.left)) {
11427
+ const newNode = this.createNode(key, value);
11428
+ if (!this.isRealNode(newNode)) return void 0;
11429
+ this._attachNewNode(succ, "left", newNode);
11430
+ if (this._isMapMode) {
11431
+ if (value !== void 0) this._store.set(key, value);
11432
+ else this._setValue(key, value);
11433
+ }
11434
+ this._size++;
11435
+ const NIL = this.NIL;
11436
+ const hMin = this._header._left ?? NIL;
11437
+ if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
11438
+ const hMax = this._header._right ?? NIL;
11439
+ if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
11440
+ return newNode;
11441
+ }
11442
+ return this._setKVNode(key, value)?.node;
11443
+ }
11444
+ /**
11445
+ * Boolean wrapper for setWithHintNode.
11446
+ * @remarks Time O(log n) average, Space O(1)
11447
+ */
11448
+ setWithHint(key, value, hint) {
11449
+ return this.setWithHintNode(key, value, hint) !== void 0;
11450
+ }
11451
+ /**
11452
+ * Insert or update a key/value (map mode) or key-only (set mode).
11453
+ *
11454
+ * This method is optimized for:
11455
+ * - monotonic inserts via min/max boundary fast paths
11456
+ * - updates via a single-pass search (no double walk)
11457
+ *
11458
+ * @remarks Time O(log n) average, Space O(1)
11014
11459
  */
11015
11460
  set(keyNodeOrEntry, value) {
11461
+ if (!this.isNode(keyNodeOrEntry)) {
11462
+ if (keyNodeOrEntry === null || keyNodeOrEntry === void 0) return false;
11463
+ if (this.isEntry(keyNodeOrEntry)) {
11464
+ const key = keyNodeOrEntry[0];
11465
+ if (key === null || key === void 0) return false;
11466
+ const nextValue = value ?? keyNodeOrEntry[1];
11467
+ return this._setKV(key, nextValue);
11468
+ }
11469
+ return this._setKV(keyNodeOrEntry, value);
11470
+ }
11016
11471
  const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
11017
11472
  if (!this.isRealNode(newNode)) return false;
11018
11473
  const insertStatus = this._insert(newNode);
@@ -11034,19 +11489,23 @@ var RedBlackTree = class extends BST {
11034
11489
  }
11035
11490
  /**
11036
11491
  * Delete a node by key/node/entry and rebalance as needed.
11037
- * @remarks Time O(log n), Space O(1)
11038
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node to delete.
11492
+ * @remarks Time O(log n) average, Space O(1)
11493
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
11039
11494
  * @returns Array with deletion metadata (removed node, rebalancing hint if any).
11040
11495
  */
11041
- delete(keyNodeOrEntry) {
11042
- if (keyNodeOrEntry === null) return [];
11496
+ delete(keyNodeEntryRawOrPredicate) {
11497
+ if (keyNodeEntryRawOrPredicate === null) return [];
11043
11498
  const results = [];
11044
11499
  let nodeToDelete;
11045
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
11046
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
11500
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
11501
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
11047
11502
  if (!nodeToDelete) {
11048
11503
  return results;
11049
11504
  }
11505
+ const willDeleteMin = nodeToDelete === this._minNode;
11506
+ const willDeleteMax = nodeToDelete === this._maxNode;
11507
+ const nextMin = willDeleteMin ? this._successorOf(nodeToDelete) : void 0;
11508
+ const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : void 0;
11050
11509
  let originalColor = nodeToDelete.color;
11051
11510
  let replacementNode;
11052
11511
  if (!this.isRealNode(nodeToDelete.left)) {
@@ -11085,6 +11544,19 @@ var RedBlackTree = class extends BST {
11085
11544
  }
11086
11545
  if (this._isMapMode) this._store.delete(nodeToDelete.key);
11087
11546
  this._size--;
11547
+ if (this._size <= 0) {
11548
+ this._setMinCache(void 0);
11549
+ this._setMaxCache(void 0);
11550
+ } else {
11551
+ if (willDeleteMin) this._setMinCache(nextMin);
11552
+ if (willDeleteMax) this._setMaxCache(nextMax);
11553
+ if (!this._minNode || !this.isRealNode(this._minNode)) {
11554
+ this._setMinCache(this.isRealNode(this._root) ? this.getLeftMost((n) => n, this._root) : void 0);
11555
+ }
11556
+ if (!this._maxNode || !this.isRealNode(this._maxNode)) {
11557
+ this._setMaxCache(this.isRealNode(this._root) ? this.getRightMost((n) => n, this._root) : void 0);
11558
+ }
11559
+ }
11088
11560
  if (originalColor === "BLACK") {
11089
11561
  this._deleteFixup(replacementNode);
11090
11562
  }
@@ -11093,7 +11565,7 @@ var RedBlackTree = class extends BST {
11093
11565
  }
11094
11566
  /**
11095
11567
  * Transform entries into a like-kind red-black tree with possibly different key/value types.
11096
- * @remarks Time O(n), Space O(n)
11568
+ * @remarks Time O(n) average, Space O(n)
11097
11569
  * @template MK
11098
11570
  * @template MV
11099
11571
  * @template MR
@@ -11110,40 +11582,61 @@ var RedBlackTree = class extends BST {
11110
11582
  }
11111
11583
  return out;
11112
11584
  }
11585
+ /**
11586
+ * (Internal) Create an empty instance of the same concrete tree type.
11587
+ * @remarks Time O(1) average, Space O(1)
11588
+ */
11113
11589
  _createInstance(options) {
11114
11590
  const Ctor = this.constructor;
11115
11591
  return new Ctor([], { ...this._snapshotOptions(), ...options ?? {} });
11116
11592
  }
11593
+ /**
11594
+ * (Internal) Create a like-kind tree (same concrete class) populated from an iterable.
11595
+ * @remarks Time O(m log m) average (m = iterable length), Space O(m)
11596
+ */
11117
11597
  _createLike(iter = [], options) {
11118
11598
  const Ctor = this.constructor;
11119
11599
  return new Ctor(iter, { ...this._snapshotOptions(), ...options ?? {} });
11120
11600
  }
11601
+ /**
11602
+ * (Internal) Set the root pointer and keep header.parent in sync.
11603
+ * @remarks Time O(1), Space O(1)
11604
+ */
11121
11605
  _setRoot(v) {
11606
+ const NIL = this.NIL;
11122
11607
  if (v) {
11123
11608
  v.parent = void 0;
11124
11609
  }
11125
11610
  this._root = v;
11611
+ this._header.parent = v ?? NIL;
11126
11612
  }
11613
+ /**
11614
+ * (Internal) Replace a node in place while preserving its color.
11615
+ * @remarks Time O(1) average, Space O(1)
11616
+ */
11127
11617
  _replaceNode(oldNode, newNode) {
11128
11618
  newNode.color = oldNode.color;
11129
11619
  return super._replaceNode(oldNode, newNode);
11130
11620
  }
11131
11621
  /**
11132
11622
  * (Protected) Standard BST insert followed by red-black fix-up.
11133
- * @remarks Time O(log n), Space O(1)
11623
+ * @remarks Time O(log n) average, Space O(1)
11134
11624
  * @param node - Node to insert.
11135
11625
  * @returns Status string: 'CREATED' or 'UPDATED'.
11136
11626
  */
11137
11627
  _insert(node) {
11138
- let current = this.root ?? this.NIL;
11139
- let parent = void 0;
11140
- while (current !== this.NIL) {
11628
+ const NIL = this.NIL;
11629
+ const cmp = this._compare.bind(this);
11630
+ let current = this._header.parent ?? NIL;
11631
+ let parent;
11632
+ let lastCompared = 0;
11633
+ while (current !== NIL) {
11141
11634
  parent = current;
11142
- const compared = this._compare(node.key, current.key);
11143
- if (compared < 0) {
11144
- current = current.left ?? this.NIL;
11145
- } else if (compared > 0) {
11146
- current = current.right ?? this.NIL;
11635
+ lastCompared = cmp(node.key, current.key);
11636
+ if (lastCompared < 0) {
11637
+ current = current.left ?? NIL;
11638
+ } else if (lastCompared > 0) {
11639
+ current = current.right ?? NIL;
11147
11640
  } else {
11148
11641
  this._replaceNode(current, node);
11149
11642
  return "UPDATED";
@@ -11152,13 +11645,13 @@ var RedBlackTree = class extends BST {
11152
11645
  node.parent = parent;
11153
11646
  if (!parent) {
11154
11647
  this._setRoot(node);
11155
- } else if (this._compare(node.key, parent.key) < 0) {
11648
+ } else if (lastCompared < 0) {
11156
11649
  parent.left = node;
11157
11650
  } else {
11158
11651
  parent.right = node;
11159
11652
  }
11160
- node.left = this.NIL;
11161
- node.right = this.NIL;
11653
+ node.left = NIL;
11654
+ node.right = NIL;
11162
11655
  node.color = "RED";
11163
11656
  this._insertFixup(node);
11164
11657
  return "CREATED";
@@ -11184,55 +11677,66 @@ var RedBlackTree = class extends BST {
11184
11677
  }
11185
11678
  /**
11186
11679
  * (Protected) Restore red-black properties after insertion (recolor/rotate).
11187
- * @remarks Time O(log n), Space O(1)
11680
+ * @remarks Time O(log n) average, Space O(1)
11188
11681
  * @param z - Recently inserted node.
11189
11682
  * @returns void
11190
11683
  */
11191
11684
  _insertFixup(z) {
11192
- while (z?.parent?.color === "RED") {
11193
- if (z.parent === z.parent.parent?.left) {
11194
- const y = z.parent.parent.right;
11685
+ const leftRotate = this._leftRotate.bind(this);
11686
+ const rightRotate = this._rightRotate.bind(this);
11687
+ while (z) {
11688
+ const p = z.parent;
11689
+ if (!p || p.color !== "RED") break;
11690
+ const gp = p.parent;
11691
+ if (!gp) break;
11692
+ if (p === gp.left) {
11693
+ const y = gp.right;
11195
11694
  if (y?.color === "RED") {
11196
- z.parent.color = "BLACK";
11695
+ p.color = "BLACK";
11197
11696
  y.color = "BLACK";
11198
- z.parent.parent.color = "RED";
11199
- z = z.parent.parent;
11200
- } else {
11201
- if (z === z.parent.right) {
11202
- z = z.parent;
11203
- this._leftRotate(z);
11204
- }
11205
- if (z && z.parent && z.parent.parent) {
11206
- z.parent.color = "BLACK";
11207
- z.parent.parent.color = "RED";
11208
- this._rightRotate(z.parent.parent);
11209
- }
11697
+ gp.color = "RED";
11698
+ z = gp;
11699
+ continue;
11700
+ }
11701
+ if (z === p.right) {
11702
+ z = p;
11703
+ leftRotate(z);
11704
+ }
11705
+ const p2 = z?.parent;
11706
+ const gp2 = p2?.parent;
11707
+ if (p2 && gp2) {
11708
+ p2.color = "BLACK";
11709
+ gp2.color = "RED";
11710
+ rightRotate(gp2);
11210
11711
  }
11211
11712
  } else {
11212
- const y = z?.parent?.parent?.left ?? void 0;
11713
+ const y = gp.left;
11213
11714
  if (y?.color === "RED") {
11214
- z.parent.color = "BLACK";
11715
+ p.color = "BLACK";
11215
11716
  y.color = "BLACK";
11216
- z.parent.parent.color = "RED";
11217
- z = z.parent.parent;
11218
- } else {
11219
- if (z === z.parent.left) {
11220
- z = z.parent;
11221
- this._rightRotate(z);
11222
- }
11223
- if (z && z.parent && z.parent.parent) {
11224
- z.parent.color = "BLACK";
11225
- z.parent.parent.color = "RED";
11226
- this._leftRotate(z.parent.parent);
11227
- }
11717
+ gp.color = "RED";
11718
+ z = gp;
11719
+ continue;
11720
+ }
11721
+ if (z === p.left) {
11722
+ z = p;
11723
+ rightRotate(z);
11724
+ }
11725
+ const p2 = z?.parent;
11726
+ const gp2 = p2?.parent;
11727
+ if (p2 && gp2) {
11728
+ p2.color = "BLACK";
11729
+ gp2.color = "RED";
11730
+ leftRotate(gp2);
11228
11731
  }
11229
11732
  }
11733
+ break;
11230
11734
  }
11231
11735
  if (this.isRealNode(this._root)) this._root.color = "BLACK";
11232
11736
  }
11233
11737
  /**
11234
11738
  * (Protected) Restore red-black properties after deletion (recolor/rotate).
11235
- * @remarks Time O(log n), Space O(1)
11739
+ * @remarks Time O(log n) average, Space O(1)
11236
11740
  * @param node - Child that replaced the deleted node (may be undefined).
11237
11741
  * @returns void
11238
11742
  */
@@ -12136,16 +12640,16 @@ var TreeCounter = class extends RedBlackTree {
12136
12640
  /**
12137
12641
  * Delete a node (or decrement its count) and rebalance if needed.
12138
12642
  * @remarks Time O(log N), Space O(1)
12139
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node.
12643
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node.
12140
12644
  * @param [ignoreCount] - If true, remove the node regardless of its count.
12141
12645
  * @returns Array of deletion results including deleted node and a rebalance hint when present.
12142
12646
  */
12143
- delete(keyNodeOrEntry, ignoreCount = false) {
12144
- if (keyNodeOrEntry === null) return [];
12647
+ delete(keyNodeEntryRawOrPredicate, ignoreCount = false) {
12648
+ if (keyNodeEntryRawOrPredicate === null) return [];
12145
12649
  const results = [];
12146
12650
  let nodeToDelete;
12147
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
12148
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
12651
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
12652
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
12149
12653
  if (!nodeToDelete) {
12150
12654
  return results;
12151
12655
  }
@@ -12188,7 +12692,6 @@ var TreeCounter = class extends RedBlackTree {
12188
12692
  if (ignoreCount || nodeToDelete.count <= 1) {
12189
12693
  if (successor.right !== null) {
12190
12694
  this._transplant(successor, successor.right);
12191
- this._count -= nodeToDelete.count;
12192
12695
  }
12193
12696
  } else {
12194
12697
  nodeToDelete.count--;
@@ -12291,6 +12794,11 @@ var TreeCounter = class extends RedBlackTree {
12291
12794
  const out = this._createInstance();
12292
12795
  this._clone(out);
12293
12796
  out._count = this._count;
12797
+ for (const node of this.dfs((n) => n, "IN")) {
12798
+ if (!node) continue;
12799
+ const outNode = out.getNode(node.key);
12800
+ if (outNode) outNode.count = node.count;
12801
+ }
12294
12802
  return out;
12295
12803
  }
12296
12804
  /**