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.
- package/.github/workflows/ci.yml +9 -0
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/README_CN.md +1 -1
- package/dist/cjs/index.cjs +584 -76
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +588 -79
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +584 -76
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +588 -79
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/types/data-structures/base/linear-base.d.ts +6 -6
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +3 -4
- package/dist/types/data-structures/binary-tree/bst.d.ts +2 -1
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +150 -20
- package/dist/types/data-structures/binary-tree/tree-counter.d.ts +3 -3
- package/dist/types/interfaces/binary-tree.d.ts +1 -1
- package/dist/umd/data-structure-typed.js +588 -79
- package/dist/umd/data-structure-typed.js.map +1 -1
- package/dist/umd/data-structure-typed.min.js +3 -3
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +4 -3
- package/src/data-structures/base/linear-base.ts +2 -12
- package/src/data-structures/binary-tree/binary-tree.ts +5 -6
- package/src/data-structures/binary-tree/bst.ts +79 -4
- package/src/data-structures/binary-tree/red-black-tree.ts +583 -73
- package/src/data-structures/binary-tree/tree-counter.ts +21 -9
- package/src/data-structures/queue/deque.ts +10 -0
- package/src/interfaces/binary-tree.ts +1 -1
- package/test/unit/data-structures/base/iterable-element-base.coverage.test.ts +106 -0
- package/test/unit/data-structures/base/iterable-element-base.more-branches.coverage.test.ts +61 -0
- package/test/unit/data-structures/base/linear-base.array.coverage.test.ts +168 -0
- package/test/unit/data-structures/base/linear-base.concat-else.coverage.test.ts +82 -0
- package/test/unit/data-structures/base/linear-base.coverage.test.ts +72 -0
- package/test/unit/data-structures/base/linear-base.more-branches.coverage.test.ts +417 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches-3.coverage.test.ts +146 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches.coverage.test.ts +93 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.coverage.test.ts +108 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.more-branches-2.coverage.test.ts +85 -0
- package/test/unit/data-structures/binary-tree/avl-tree-node.familyPosition-root-left.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/avl-tree.more-branches-2.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/binary-indexed-tree.more-branches.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/binary-tree.more-branches.coverage.test.ts +56 -0
- package/test/unit/data-structures/binary-tree/binary-tree.remaining-branches.coverage.test.ts +229 -0
- package/test/unit/data-structures/binary-tree/bst.bound-by-predicate.coverage.test.ts +33 -0
- package/test/unit/data-structures/binary-tree/bst.coverage.test.ts +94 -0
- package/test/unit/data-structures/binary-tree/bst.deletebykey.coverage.test.ts +70 -0
- package/test/unit/data-structures/binary-tree/bst.deletewhere.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/bst.floor-lower-predicate.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.floor-setmany.coverage.test.ts +72 -0
- package/test/unit/data-structures/binary-tree/bst.getnode.range-ensure.coverage.test.ts +22 -0
- package/test/unit/data-structures/binary-tree/bst.misc-branches.coverage.test.ts +100 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-2.coverage.test.ts +133 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-3.coverage.test.ts +45 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-4.coverage.test.ts +36 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-5.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/bst.more.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/bst.node-family.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.range-pruning.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/bst.search-fastpath.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/bst.test.ts +25 -55
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-corruption-repair.coverage.test.ts +66 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-max-update.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-null.coverage.test.ts +53 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-stale-cache.coverage.test.ts +25 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-update.coverage.test.ts +23 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-delete.coverage.test.ts +49 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-edge.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-stale-insert.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.coverage.test.ts +334 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-fixup.coverage.test.ts +68 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-successor.coverage.test.ts +75 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.factories.coverage.test.ts +26 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-compare-update.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-no-update.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-nullish.coverage.test.ts +61 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts +35 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-more.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint.coverage.test.ts +60 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-header-parent-nullish.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.internal-walk.coverage.test.ts +57 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.minmax-cache.test.ts +65 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.misc-inputs.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-2.coverage.test.ts +121 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-3.coverage.test.ts +55 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-4.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.predsucc.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts +123 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.set-inputs.coverage.test.ts +64 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts +79 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.update-branches.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/segment-tree.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/binary-tree/tree-counter.coverage.test.ts +115 -0
- package/test/unit/data-structures/binary-tree/tree-counter.more-branches.coverage.test.ts +244 -0
- package/test/unit/data-structures/binary-tree/tree-counter.test.ts +4 -2
- package/test/unit/data-structures/binary-tree/tree-multi-map.coverage.test.ts +104 -0
- package/test/unit/data-structures/binary-tree/tree-multi-map.more-branches-2.coverage.test.ts +59 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-2.coverage.test.ts +40 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-3.coverage.test.ts +65 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-4.coverage.test.ts +98 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-5.coverage.test.ts +51 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches.coverage.test.ts +62 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-2.coverage.test.ts +38 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-3.coverage.test.ts +25 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches.coverage.test.ts +82 -0
- package/test/unit/data-structures/graph/map-graph.more-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches-2.coverage.test.ts +35 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches.coverage.test.ts +87 -0
- package/test/unit/data-structures/hash/hash-map.more-branches.coverage.test.ts +64 -0
- package/test/unit/data-structures/hash/hash-map.toEntryFn-branch.coverage.test.ts +9 -0
- package/test/unit/data-structures/heap/heap.misc-branches.coverage.test.ts +110 -0
- package/test/unit/data-structures/heap/heap.remaining-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/heap/max-heap.coverage.test.ts +29 -0
- package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts +72 -0
- package/test/unit/data-structures/linked-list/linked-list.unshiftMany-else.coverage.test.ts +15 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.coverage.test.ts +221 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts +86 -0
- package/test/unit/data-structures/linked-list/skip-linked-list.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/matrix/matrix.more-branches.coverage.test.ts +81 -0
- package/test/unit/data-structures/matrix/matrix.pivotElement-nullish.coverage.test.ts +28 -0
- package/test/unit/data-structures/priority-queue/max-priority-queue.more-branches.coverage.test.ts +10 -0
- package/test/unit/data-structures/priority-queue/priority-queue.coverage.test.ts +21 -0
- package/test/unit/data-structures/queue/deque.coverage.test.ts +173 -0
- package/test/unit/data-structures/queue/deque.more-branches-2.coverage.test.ts +39 -0
- package/test/unit/data-structures/queue/deque.more-branches-3.coverage.test.ts +9 -0
- package/test/unit/data-structures/queue/deque.more-branches.coverage.test.ts +95 -0
- package/test/unit/data-structures/queue/queue.coverage.test.ts +138 -0
- package/test/unit/data-structures/queue/queue.more-branches-2.coverage.test.ts +27 -0
- package/test/unit/data-structures/stack/stack.coverage.test.ts +112 -0
- package/test/unit/data-structures/tree/tree.more-branches.coverage.test.ts +9 -0
- package/test/unit/data-structures/trie/trie.more-branches-2.coverage.test.ts +51 -0
- package/test/utils/patch.ts +33 -0
|
@@ -1398,6 +1398,12 @@ var _LinearLinkedBase = class _LinearLinkedBase extends LinearBase {
|
|
|
1398
1398
|
}
|
|
1399
1399
|
return -1;
|
|
1400
1400
|
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Concatenate lists/elements preserving order.
|
|
1403
|
+
* @param items - Elements or `LinearBase` instances.
|
|
1404
|
+
* @returns New list with combined elements (`this` type).
|
|
1405
|
+
* @remarks Time O(sum(length)), Space O(sum(length))
|
|
1406
|
+
*/
|
|
1401
1407
|
concat(...items) {
|
|
1402
1408
|
const newList = this.clone();
|
|
1403
1409
|
for (const item of items) {
|
|
@@ -4220,6 +4226,12 @@ var _Deque = class _Deque extends LinearBase {
|
|
|
4220
4226
|
*/
|
|
4221
4227
|
_setBucketSize(size) {
|
|
4222
4228
|
this._bucketSize = size;
|
|
4229
|
+
if (this._length === 0) {
|
|
4230
|
+
this._buckets = [new Array(this._bucketSize)];
|
|
4231
|
+
this._bucketCount = 1;
|
|
4232
|
+
this._bucketFirst = this._bucketLast = 0;
|
|
4233
|
+
this._firstInBucket = this._lastInBucket = this._bucketSize >> 1;
|
|
4234
|
+
}
|
|
4223
4235
|
}
|
|
4224
4236
|
/**
|
|
4225
4237
|
* (Protected) Iterate elements from front to back.
|
|
@@ -7272,7 +7284,6 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
|
|
|
7272
7284
|
* @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).
|
|
7273
7285
|
*
|
|
7274
7286
|
* @param keysNodesEntriesOrRaws - An iterable of items to set.
|
|
7275
|
-
* @param [values] - An optional parallel iterable of values.
|
|
7276
7287
|
* @returns An array of booleans indicating the success of each individual `set` operation.
|
|
7277
7288
|
*/
|
|
7278
7289
|
addMany(keysNodesEntriesOrRaws) {
|
|
@@ -7329,13 +7340,13 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
|
|
|
7329
7340
|
* Deletes a node from the tree.
|
|
7330
7341
|
* @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).
|
|
7331
7342
|
*
|
|
7332
|
-
* @param
|
|
7343
|
+
* @param keyNodeEntryRawOrPredicate - The node to delete.
|
|
7333
7344
|
* @returns An array containing deletion results (for compatibility with self-balancing trees).
|
|
7334
7345
|
*/
|
|
7335
|
-
delete(
|
|
7346
|
+
delete(keyNodeEntryRawOrPredicate) {
|
|
7336
7347
|
const deletedResult = [];
|
|
7337
7348
|
if (!this._root) return deletedResult;
|
|
7338
|
-
const curr = this.getNode(
|
|
7349
|
+
const curr = this.getNode(keyNodeEntryRawOrPredicate);
|
|
7339
7350
|
if (!curr) return deletedResult;
|
|
7340
7351
|
const parent = curr == null ? void 0 : curr.parent;
|
|
7341
7352
|
let needBalanced;
|
|
@@ -7519,7 +7530,7 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
|
|
|
7519
7530
|
}
|
|
7520
7531
|
return true;
|
|
7521
7532
|
}, "checkBST");
|
|
7522
|
-
const isStandardBST = checkBST(
|
|
7533
|
+
const isStandardBST = checkBST();
|
|
7523
7534
|
const isInverseBST = checkBST(true);
|
|
7524
7535
|
return isStandardBST || isInverseBST;
|
|
7525
7536
|
}
|
|
@@ -8750,8 +8761,40 @@ var _BST = class _BST extends BinaryTree {
|
|
|
8750
8761
|
* @returns The first matching node, or undefined if not found.
|
|
8751
8762
|
*/
|
|
8752
8763
|
getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
|
|
8753
|
-
var _a;
|
|
8754
|
-
|
|
8764
|
+
var _a, _b;
|
|
8765
|
+
if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === void 0) return void 0;
|
|
8766
|
+
if (this._isPredicate(keyNodeEntryOrPredicate)) {
|
|
8767
|
+
return (_a = this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0]) != null ? _a : void 0;
|
|
8768
|
+
}
|
|
8769
|
+
if (keyNodeEntryOrPredicate instanceof Range) {
|
|
8770
|
+
return (_b = this.getNodes(
|
|
8771
|
+
keyNodeEntryOrPredicate,
|
|
8772
|
+
true,
|
|
8773
|
+
startNode,
|
|
8774
|
+
iterationType
|
|
8775
|
+
)[0]) != null ? _b : void 0;
|
|
8776
|
+
}
|
|
8777
|
+
let targetKey;
|
|
8778
|
+
if (this.isNode(keyNodeEntryOrPredicate)) {
|
|
8779
|
+
targetKey = keyNodeEntryOrPredicate.key;
|
|
8780
|
+
} else if (this.isEntry(keyNodeEntryOrPredicate)) {
|
|
8781
|
+
const k = keyNodeEntryOrPredicate[0];
|
|
8782
|
+
if (k === null || k === void 0) return void 0;
|
|
8783
|
+
targetKey = k;
|
|
8784
|
+
} else {
|
|
8785
|
+
targetKey = keyNodeEntryOrPredicate;
|
|
8786
|
+
}
|
|
8787
|
+
const start = this.ensureNode(startNode);
|
|
8788
|
+
if (!start) return void 0;
|
|
8789
|
+
const NIL = this._NIL;
|
|
8790
|
+
let cur = start;
|
|
8791
|
+
const cmpFn = this._comparator;
|
|
8792
|
+
while (cur && cur !== NIL) {
|
|
8793
|
+
const c = cmpFn(targetKey, cur.key);
|
|
8794
|
+
if (c === 0) return cur;
|
|
8795
|
+
cur = c < 0 ? cur._left : cur._right;
|
|
8796
|
+
}
|
|
8797
|
+
return void 0;
|
|
8755
8798
|
}
|
|
8756
8799
|
/**
|
|
8757
8800
|
* Searches the tree for nodes matching a predicate, key, or range.
|
|
@@ -8772,8 +8815,30 @@ var _BST = class _BST extends BinaryTree {
|
|
|
8772
8815
|
if (keyNodeEntryOrPredicate === null) return [];
|
|
8773
8816
|
startNode = this.ensureNode(startNode);
|
|
8774
8817
|
if (!startNode) return [];
|
|
8775
|
-
let predicate;
|
|
8776
8818
|
const isRange = this.isRange(keyNodeEntryOrPredicate);
|
|
8819
|
+
const isPred = !isRange && this._isPredicate(keyNodeEntryOrPredicate);
|
|
8820
|
+
if (!isRange && !isPred) {
|
|
8821
|
+
let targetKey;
|
|
8822
|
+
if (this.isNode(keyNodeEntryOrPredicate)) {
|
|
8823
|
+
targetKey = keyNodeEntryOrPredicate.key;
|
|
8824
|
+
} else if (this.isEntry(keyNodeEntryOrPredicate)) {
|
|
8825
|
+
const k = keyNodeEntryOrPredicate[0];
|
|
8826
|
+
if (k !== null && k !== void 0) targetKey = k;
|
|
8827
|
+
} else {
|
|
8828
|
+
targetKey = keyNodeEntryOrPredicate;
|
|
8829
|
+
}
|
|
8830
|
+
if (targetKey === void 0) return [];
|
|
8831
|
+
const NIL = this._NIL;
|
|
8832
|
+
const cmpFn = this._comparator;
|
|
8833
|
+
let cur = startNode;
|
|
8834
|
+
while (cur && cur !== NIL) {
|
|
8835
|
+
const c = cmpFn(targetKey, cur.key);
|
|
8836
|
+
if (c === 0) return [callback(cur)];
|
|
8837
|
+
cur = c < 0 ? cur._left : cur._right;
|
|
8838
|
+
}
|
|
8839
|
+
return [];
|
|
8840
|
+
}
|
|
8841
|
+
let predicate;
|
|
8777
8842
|
if (isRange) {
|
|
8778
8843
|
predicate = /* @__PURE__ */ __name((node) => {
|
|
8779
8844
|
if (!node) return false;
|
|
@@ -9660,7 +9725,6 @@ var _BST = class _BST extends BinaryTree {
|
|
|
9660
9725
|
* @returns True if the node was found and deleted, false otherwise.
|
|
9661
9726
|
*/
|
|
9662
9727
|
_deleteByKey(key) {
|
|
9663
|
-
var _a;
|
|
9664
9728
|
let node = this._root;
|
|
9665
9729
|
while (node) {
|
|
9666
9730
|
const cmp = this._compare(node.key, key);
|
|
@@ -9699,7 +9763,7 @@ var _BST = class _BST extends BinaryTree {
|
|
|
9699
9763
|
succ.left = node.left;
|
|
9700
9764
|
if (succ.left) succ.left.parent = succ;
|
|
9701
9765
|
}
|
|
9702
|
-
this._size = Math.max(0,
|
|
9766
|
+
this._size = Math.max(0, this._size - 1);
|
|
9703
9767
|
return true;
|
|
9704
9768
|
}
|
|
9705
9769
|
};
|
|
@@ -10806,12 +10870,11 @@ var AVLTree = _AVLTree;
|
|
|
10806
10870
|
// src/data-structures/binary-tree/red-black-tree.ts
|
|
10807
10871
|
var _RedBlackTreeNode = class _RedBlackTreeNode {
|
|
10808
10872
|
/**
|
|
10809
|
-
* Create a Red-Black Tree
|
|
10810
|
-
* @remarks Time O(
|
|
10811
|
-
* @param key -
|
|
10812
|
-
* @param [value]-
|
|
10813
|
-
* @param color -
|
|
10814
|
-
* @returns New RedBlackTree instance.
|
|
10873
|
+
* Create a Red-Black Tree node.
|
|
10874
|
+
* @remarks Time O(1), Space O(1)
|
|
10875
|
+
* @param key - Node key.
|
|
10876
|
+
* @param [value] - Node value (unused in map mode trees).
|
|
10877
|
+
* @param color - Node color.
|
|
10815
10878
|
*/
|
|
10816
10879
|
constructor(key, value, color = "BLACK") {
|
|
10817
10880
|
__publicField(this, "key");
|
|
@@ -10944,7 +11007,29 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
10944
11007
|
constructor(keysNodesEntriesOrRaws = [], options) {
|
|
10945
11008
|
super([], options);
|
|
10946
11009
|
__publicField(this, "_root");
|
|
11010
|
+
/**
|
|
11011
|
+
* (Internal) Header sentinel:
|
|
11012
|
+
* - header.parent -> root
|
|
11013
|
+
* - header._left -> min (or NIL)
|
|
11014
|
+
* - header._right -> max (or NIL)
|
|
11015
|
+
*
|
|
11016
|
+
* IMPORTANT:
|
|
11017
|
+
* - This header is NOT part of the actual tree.
|
|
11018
|
+
* - Do NOT use `header.left` / `header.right` accessors for wiring: those setters update `NIL.parent`
|
|
11019
|
+
* and can corrupt sentinel invariants / cause hangs. Only touch `header._left/_right`.
|
|
11020
|
+
*/
|
|
11021
|
+
__publicField(this, "_header");
|
|
11022
|
+
/**
|
|
11023
|
+
* (Internal) Cache of the current minimum and maximum nodes.
|
|
11024
|
+
* Used for fast-path insert/update when keys are monotonic or near-boundary.
|
|
11025
|
+
*/
|
|
11026
|
+
__publicField(this, "_minNode");
|
|
11027
|
+
__publicField(this, "_maxNode");
|
|
10947
11028
|
this._root = this.NIL;
|
|
11029
|
+
this._header = new RedBlackTreeNode(void 0, void 0, "BLACK");
|
|
11030
|
+
this._header.parent = this.NIL;
|
|
11031
|
+
this._header._left = this.NIL;
|
|
11032
|
+
this._header._right = this.NIL;
|
|
10948
11033
|
if (keysNodesEntriesOrRaws) {
|
|
10949
11034
|
this.setMany(keysNodesEntriesOrRaws);
|
|
10950
11035
|
}
|
|
@@ -10982,18 +11067,390 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
10982
11067
|
* @remarks Time O(n), Space O(1)
|
|
10983
11068
|
* @returns void
|
|
10984
11069
|
*/
|
|
11070
|
+
/**
|
|
11071
|
+
* Remove all nodes and clear internal caches.
|
|
11072
|
+
* @remarks Time O(n) average, Space O(1)
|
|
11073
|
+
*/
|
|
10985
11074
|
clear() {
|
|
10986
11075
|
super.clear();
|
|
10987
11076
|
this._root = this.NIL;
|
|
11077
|
+
this._header.parent = this.NIL;
|
|
11078
|
+
this._setMinCache(void 0);
|
|
11079
|
+
this._setMaxCache(void 0);
|
|
10988
11080
|
}
|
|
10989
11081
|
/**
|
|
10990
|
-
*
|
|
10991
|
-
*
|
|
10992
|
-
*
|
|
10993
|
-
* @
|
|
10994
|
-
|
|
11082
|
+
* (Internal) Find a node by key using a tight BST walk (no allocations).
|
|
11083
|
+
*
|
|
11084
|
+
* NOTE: This uses `header.parent` as the canonical root pointer.
|
|
11085
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11086
|
+
*/
|
|
11087
|
+
_findNodeByKey(key) {
|
|
11088
|
+
var _a, _b, _c;
|
|
11089
|
+
const NIL = this.NIL;
|
|
11090
|
+
const cmp = this._compare.bind(this);
|
|
11091
|
+
let cur = (_a = this._header.parent) != null ? _a : NIL;
|
|
11092
|
+
while (cur !== NIL) {
|
|
11093
|
+
const c = cmp(key, cur.key);
|
|
11094
|
+
if (c < 0) cur = (_b = cur.left) != null ? _b : NIL;
|
|
11095
|
+
else if (c > 0) cur = (_c = cur.right) != null ? _c : NIL;
|
|
11096
|
+
else return cur;
|
|
11097
|
+
}
|
|
11098
|
+
return void 0;
|
|
11099
|
+
}
|
|
11100
|
+
/**
|
|
11101
|
+
* (Internal) In-order predecessor of a node in a BST.
|
|
11102
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11103
|
+
*/
|
|
11104
|
+
_predecessorOf(node) {
|
|
11105
|
+
const NIL = this.NIL;
|
|
11106
|
+
if (node.left && node.left !== NIL) {
|
|
11107
|
+
let cur2 = node.left;
|
|
11108
|
+
while (cur2.right && cur2.right !== NIL) cur2 = cur2.right;
|
|
11109
|
+
return cur2;
|
|
11110
|
+
}
|
|
11111
|
+
let cur = node;
|
|
11112
|
+
let p = node.parent;
|
|
11113
|
+
while (p && cur === p.left) {
|
|
11114
|
+
cur = p;
|
|
11115
|
+
p = p.parent;
|
|
11116
|
+
}
|
|
11117
|
+
return p;
|
|
11118
|
+
}
|
|
11119
|
+
/**
|
|
11120
|
+
* (Internal) In-order successor of a node in a BST.
|
|
11121
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11122
|
+
*/
|
|
11123
|
+
_successorOf(node) {
|
|
11124
|
+
const NIL = this.NIL;
|
|
11125
|
+
if (node.right && node.right !== NIL) {
|
|
11126
|
+
let cur2 = node.right;
|
|
11127
|
+
while (cur2.left && cur2.left !== NIL) cur2 = cur2.left;
|
|
11128
|
+
return cur2;
|
|
11129
|
+
}
|
|
11130
|
+
let cur = node;
|
|
11131
|
+
let p = node.parent;
|
|
11132
|
+
while (p && cur === p.right) {
|
|
11133
|
+
cur = p;
|
|
11134
|
+
p = p.parent;
|
|
11135
|
+
}
|
|
11136
|
+
return p;
|
|
11137
|
+
}
|
|
11138
|
+
/**
|
|
11139
|
+
* (Internal) Attach a new node directly under a known parent/side (no search).
|
|
11140
|
+
*
|
|
11141
|
+
* This is a performance-oriented helper used by boundary fast paths and hinted insertion.
|
|
11142
|
+
* It will:
|
|
11143
|
+
* - wire parent/child pointers (using accessors, so parent pointers are updated)
|
|
11144
|
+
* - initialize children to NIL
|
|
11145
|
+
* - mark the new node RED, then run insert fix-up
|
|
11146
|
+
*
|
|
11147
|
+
* Precondition: the chosen slot (parent.left/parent.right) is empty (NIL/null/undefined).
|
|
11148
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11149
|
+
*/
|
|
11150
|
+
_attachNewNode(parent, side, node) {
|
|
11151
|
+
const NIL = this.NIL;
|
|
11152
|
+
node.parent = parent;
|
|
11153
|
+
if (side === "left") parent.left = node;
|
|
11154
|
+
else parent.right = node;
|
|
11155
|
+
node.left = NIL;
|
|
11156
|
+
node.right = NIL;
|
|
11157
|
+
node.color = "RED";
|
|
11158
|
+
this._insertFixup(node);
|
|
11159
|
+
if (this.isRealNode(this._root)) this._root.color = "BLACK";
|
|
11160
|
+
}
|
|
11161
|
+
/**
|
|
11162
|
+
* (Internal) a single source of truth for min/max is header._left/_right.
|
|
11163
|
+
* Keep legacy _minNode/_maxNode mirrored for compatibility.
|
|
11164
|
+
* @remarks Time O(1), Space O(1)
|
|
11165
|
+
*/
|
|
11166
|
+
/**
|
|
11167
|
+
* (Internal) Update min cache pointers (header._left is the canonical min pointer).
|
|
11168
|
+
* @remarks Time O(1), Space O(1)
|
|
11169
|
+
*/
|
|
11170
|
+
_setMinCache(node) {
|
|
11171
|
+
this._minNode = node;
|
|
11172
|
+
this._header._left = node != null ? node : this.NIL;
|
|
11173
|
+
}
|
|
11174
|
+
/**
|
|
11175
|
+
* (Internal) Update max cache pointers (header._right is the canonical max pointer).
|
|
11176
|
+
* @remarks Time O(1), Space O(1)
|
|
11177
|
+
*/
|
|
11178
|
+
_setMaxCache(node) {
|
|
11179
|
+
this._maxNode = node;
|
|
11180
|
+
this._header._right = node != null ? node : this.NIL;
|
|
11181
|
+
}
|
|
11182
|
+
/**
|
|
11183
|
+
* (Internal) Core set implementation returning the affected node.
|
|
11184
|
+
*
|
|
11185
|
+
* Hot path goals:
|
|
11186
|
+
* - Avoid double walks (search+insert): do a single traversal that either updates or inserts.
|
|
11187
|
+
* - Use header min/max caches to fast-path boundary inserts.
|
|
11188
|
+
* - Keep header._left/_right as canonical min/max pointers.
|
|
11189
|
+
*
|
|
11190
|
+
* Return value:
|
|
11191
|
+
* - `{ node, created:false }` when an existing key is updated
|
|
11192
|
+
* - `{ node, created:true }` when a new node is inserted
|
|
11193
|
+
* - `undefined` only on unexpected internal failure.
|
|
11194
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11195
|
+
*/
|
|
11196
|
+
_setKVNode(key, nextValue) {
|
|
11197
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
11198
|
+
const NIL = this.NIL;
|
|
11199
|
+
const comparator = this._comparator;
|
|
11200
|
+
const header = this._header;
|
|
11201
|
+
const minN = (_a = header._left) != null ? _a : NIL;
|
|
11202
|
+
if (minN !== NIL) {
|
|
11203
|
+
const cMin = comparator(key, minN.key);
|
|
11204
|
+
if (cMin === 0) {
|
|
11205
|
+
if (this._isMapMode) {
|
|
11206
|
+
if (nextValue !== void 0) this._store.set(key, nextValue);
|
|
11207
|
+
else this._setValue(key, nextValue);
|
|
11208
|
+
} else minN.value = nextValue;
|
|
11209
|
+
return { node: minN, created: false };
|
|
11210
|
+
}
|
|
11211
|
+
const minL = minN.left;
|
|
11212
|
+
if (cMin < 0 && (minL === NIL || minL === null || minL === void 0)) {
|
|
11213
|
+
const newNode2 = this.createNode(key, nextValue);
|
|
11214
|
+
this._attachNewNode(minN, "left", newNode2);
|
|
11215
|
+
if (this._isMapMode) {
|
|
11216
|
+
if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
|
|
11217
|
+
else this._setValue(newNode2.key, nextValue);
|
|
11218
|
+
}
|
|
11219
|
+
this._size++;
|
|
11220
|
+
this._setMinCache(newNode2);
|
|
11221
|
+
if (header._right === NIL) this._setMaxCache(newNode2);
|
|
11222
|
+
return { node: newNode2, created: true };
|
|
11223
|
+
}
|
|
11224
|
+
if (cMin > 0) {
|
|
11225
|
+
const maxN = (_b = header._right) != null ? _b : NIL;
|
|
11226
|
+
const cMax = comparator(key, maxN.key);
|
|
11227
|
+
if (cMax === 0) {
|
|
11228
|
+
if (this._isMapMode) {
|
|
11229
|
+
if (nextValue !== void 0) this._store.set(key, nextValue);
|
|
11230
|
+
else this._setValue(key, nextValue);
|
|
11231
|
+
} else maxN.value = nextValue;
|
|
11232
|
+
return { node: maxN, created: false };
|
|
11233
|
+
}
|
|
11234
|
+
const maxR = maxN.right;
|
|
11235
|
+
if (cMax > 0 && (maxR === NIL || maxR === null || maxR === void 0)) {
|
|
11236
|
+
const newNode2 = this.createNode(key, nextValue);
|
|
11237
|
+
this._attachNewNode(maxN, "right", newNode2);
|
|
11238
|
+
if (this._isMapMode) {
|
|
11239
|
+
if (nextValue !== void 0) this._store.set(newNode2.key, nextValue);
|
|
11240
|
+
else this._setValue(newNode2.key, nextValue);
|
|
11241
|
+
}
|
|
11242
|
+
this._size++;
|
|
11243
|
+
this._setMaxCache(newNode2);
|
|
11244
|
+
if (header._left === NIL) this._setMinCache(newNode2);
|
|
11245
|
+
return { node: newNode2, created: true };
|
|
11246
|
+
}
|
|
11247
|
+
}
|
|
11248
|
+
}
|
|
11249
|
+
const cmp = comparator;
|
|
11250
|
+
const isMapMode = this._isMapMode;
|
|
11251
|
+
const store = this._store;
|
|
11252
|
+
let current = (_c = this._header.parent) != null ? _c : NIL;
|
|
11253
|
+
let parent;
|
|
11254
|
+
let lastCompared = 0;
|
|
11255
|
+
while (current !== NIL) {
|
|
11256
|
+
parent = current;
|
|
11257
|
+
lastCompared = cmp(key, current.key);
|
|
11258
|
+
if (lastCompared < 0) current = (_d = current.left) != null ? _d : NIL;
|
|
11259
|
+
else if (lastCompared > 0) current = (_e = current.right) != null ? _e : NIL;
|
|
11260
|
+
else {
|
|
11261
|
+
if (isMapMode) {
|
|
11262
|
+
if (nextValue !== void 0) store.set(key, nextValue);
|
|
11263
|
+
else this._setValue(key, nextValue);
|
|
11264
|
+
} else {
|
|
11265
|
+
current.value = nextValue;
|
|
11266
|
+
}
|
|
11267
|
+
return { node: current, created: false };
|
|
11268
|
+
}
|
|
11269
|
+
}
|
|
11270
|
+
const newNode = this.createNode(key, nextValue);
|
|
11271
|
+
newNode.parent = parent;
|
|
11272
|
+
if (!parent) {
|
|
11273
|
+
this._setRoot(newNode);
|
|
11274
|
+
} else if (lastCompared < 0) {
|
|
11275
|
+
parent.left = newNode;
|
|
11276
|
+
} else {
|
|
11277
|
+
parent.right = newNode;
|
|
11278
|
+
}
|
|
11279
|
+
newNode.left = NIL;
|
|
11280
|
+
newNode.right = NIL;
|
|
11281
|
+
newNode.color = "RED";
|
|
11282
|
+
this._insertFixup(newNode);
|
|
11283
|
+
if (this.isRealNode(this._root)) this._root.color = "BLACK";
|
|
11284
|
+
else return void 0;
|
|
11285
|
+
if (isMapMode) {
|
|
11286
|
+
if (nextValue !== void 0) store.set(newNode.key, nextValue);
|
|
11287
|
+
else this._setValue(newNode.key, nextValue);
|
|
11288
|
+
}
|
|
11289
|
+
this._size++;
|
|
11290
|
+
const hMin = (_f = this._header._left) != null ? _f : NIL;
|
|
11291
|
+
const hMax = (_g = this._header._right) != null ? _g : NIL;
|
|
11292
|
+
if (hMin === NIL || hMax === NIL) {
|
|
11293
|
+
this._setMinCache(newNode);
|
|
11294
|
+
this._setMaxCache(newNode);
|
|
11295
|
+
} else if (parent === hMax && lastCompared > 0) {
|
|
11296
|
+
this._setMaxCache(newNode);
|
|
11297
|
+
} else if (parent === hMin && lastCompared < 0) {
|
|
11298
|
+
this._setMinCache(newNode);
|
|
11299
|
+
} else {
|
|
11300
|
+
if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
11301
|
+
if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
11302
|
+
}
|
|
11303
|
+
return { node: newNode, created: true };
|
|
11304
|
+
}
|
|
11305
|
+
/**
|
|
11306
|
+
* (Internal) Boolean wrapper around `_setKVNode`.
|
|
11307
|
+
*
|
|
11308
|
+
* Includes a map-mode update fast-path:
|
|
11309
|
+
* - If `isMapMode=true` and the key already exists in `_store`, then updating the value does not
|
|
11310
|
+
* require any tree search/rotation (tree shape depends only on key).
|
|
11311
|
+
* - This path is intentionally limited to `nextValue !== undefined` to preserve existing
|
|
11312
|
+
* semantics for `undefined` values.
|
|
11313
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11314
|
+
*/
|
|
11315
|
+
_setKV(key, nextValue) {
|
|
11316
|
+
if (this._isMapMode && nextValue !== void 0) {
|
|
11317
|
+
const store = this._store;
|
|
11318
|
+
if (store.has(key)) {
|
|
11319
|
+
store.set(key, nextValue);
|
|
11320
|
+
return true;
|
|
11321
|
+
}
|
|
11322
|
+
}
|
|
11323
|
+
return this._setKVNode(key, nextValue) !== void 0;
|
|
11324
|
+
}
|
|
11325
|
+
/**
|
|
11326
|
+
* Insert/update using a hint node to speed up nearby insertions.
|
|
11327
|
+
*
|
|
11328
|
+
* close to the expected insertion position (often the previously returned node in a loop).
|
|
11329
|
+
*
|
|
11330
|
+
* When the hint is a good fit (sorted / nearly-sorted insertion), this can avoid most of the
|
|
11331
|
+
* normal root-to-leaf search and reduce constant factors.
|
|
11332
|
+
*
|
|
11333
|
+
* When the hint does not match (random workloads), this will fall back to the normal set path.
|
|
11334
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11335
|
+
*/
|
|
11336
|
+
setWithHintNode(key, value, hint) {
|
|
11337
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
11338
|
+
if (!hint || !this.isRealNode(hint)) {
|
|
11339
|
+
return (_a = this._setKVNode(key, value)) == null ? void 0 : _a.node;
|
|
11340
|
+
}
|
|
11341
|
+
const cmp = this._compare.bind(this);
|
|
11342
|
+
const c0 = cmp(key, hint.key);
|
|
11343
|
+
if (c0 === 0) {
|
|
11344
|
+
if (this._isMapMode) {
|
|
11345
|
+
if (value !== void 0) this._store.set(key, value);
|
|
11346
|
+
else this._setValue(key, value);
|
|
11347
|
+
} else hint.value = value;
|
|
11348
|
+
return hint;
|
|
11349
|
+
}
|
|
11350
|
+
if (c0 < 0) {
|
|
11351
|
+
if (!this.isRealNode(hint.left)) {
|
|
11352
|
+
const newNode = this.createNode(key, value);
|
|
11353
|
+
if (!this.isRealNode(newNode)) return void 0;
|
|
11354
|
+
this._attachNewNode(hint, "left", newNode);
|
|
11355
|
+
if (this._isMapMode) {
|
|
11356
|
+
if (value !== void 0) this._store.set(key, value);
|
|
11357
|
+
else this._setValue(key, value);
|
|
11358
|
+
}
|
|
11359
|
+
this._size++;
|
|
11360
|
+
const NIL = this.NIL;
|
|
11361
|
+
const hMin = (_b = this._header._left) != null ? _b : NIL;
|
|
11362
|
+
if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
11363
|
+
const hMax = (_c = this._header._right) != null ? _c : NIL;
|
|
11364
|
+
if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
11365
|
+
return newNode;
|
|
11366
|
+
}
|
|
11367
|
+
const pred = this._predecessorOf(hint);
|
|
11368
|
+
if (pred && cmp(pred.key, key) >= 0) {
|
|
11369
|
+
return (_d = this._setKVNode(key, value)) == null ? void 0 : _d.node;
|
|
11370
|
+
}
|
|
11371
|
+
if (pred && !this.isRealNode(pred.right)) {
|
|
11372
|
+
const newNode = this.createNode(key, value);
|
|
11373
|
+
if (!this.isRealNode(newNode)) return void 0;
|
|
11374
|
+
this._attachNewNode(pred, "right", newNode);
|
|
11375
|
+
if (this._isMapMode) {
|
|
11376
|
+
if (value !== void 0) this._store.set(key, value);
|
|
11377
|
+
else this._setValue(key, value);
|
|
11378
|
+
}
|
|
11379
|
+
this._size++;
|
|
11380
|
+
const NIL = this.NIL;
|
|
11381
|
+
const hMin = (_e = this._header._left) != null ? _e : NIL;
|
|
11382
|
+
if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
11383
|
+
const hMax = (_f = this._header._right) != null ? _f : NIL;
|
|
11384
|
+
if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
11385
|
+
return newNode;
|
|
11386
|
+
}
|
|
11387
|
+
return (_g = this._setKVNode(key, value)) == null ? void 0 : _g.node;
|
|
11388
|
+
}
|
|
11389
|
+
if (!this.isRealNode(hint.right)) {
|
|
11390
|
+
const newNode = this.createNode(key, value);
|
|
11391
|
+
if (!this.isRealNode(newNode)) return void 0;
|
|
11392
|
+
this._attachNewNode(hint, "right", newNode);
|
|
11393
|
+
if (this._isMapMode) {
|
|
11394
|
+
if (value !== void 0) this._store.set(key, value);
|
|
11395
|
+
else this._setValue(key, value);
|
|
11396
|
+
}
|
|
11397
|
+
this._size++;
|
|
11398
|
+
const NIL = this.NIL;
|
|
11399
|
+
const hMin = (_h = this._header._left) != null ? _h : NIL;
|
|
11400
|
+
if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
11401
|
+
const hMax = (_i = this._header._right) != null ? _i : NIL;
|
|
11402
|
+
if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
11403
|
+
return newNode;
|
|
11404
|
+
}
|
|
11405
|
+
const succ = this._successorOf(hint);
|
|
11406
|
+
if (succ && cmp(succ.key, key) <= 0) {
|
|
11407
|
+
return (_j = this._setKVNode(key, value)) == null ? void 0 : _j.node;
|
|
11408
|
+
}
|
|
11409
|
+
if (succ && !this.isRealNode(succ.left)) {
|
|
11410
|
+
const newNode = this.createNode(key, value);
|
|
11411
|
+
if (!this.isRealNode(newNode)) return void 0;
|
|
11412
|
+
this._attachNewNode(succ, "left", newNode);
|
|
11413
|
+
if (this._isMapMode) {
|
|
11414
|
+
if (value !== void 0) this._store.set(key, value);
|
|
11415
|
+
else this._setValue(key, value);
|
|
11416
|
+
}
|
|
11417
|
+
this._size++;
|
|
11418
|
+
const NIL = this.NIL;
|
|
11419
|
+
const hMin = (_k = this._header._left) != null ? _k : NIL;
|
|
11420
|
+
if (hMin === NIL || this._compare(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
11421
|
+
const hMax = (_l = this._header._right) != null ? _l : NIL;
|
|
11422
|
+
if (hMax === NIL || this._compare(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
11423
|
+
return newNode;
|
|
11424
|
+
}
|
|
11425
|
+
return (_m = this._setKVNode(key, value)) == null ? void 0 : _m.node;
|
|
11426
|
+
}
|
|
11427
|
+
/**
|
|
11428
|
+
* Boolean wrapper for setWithHintNode.
|
|
11429
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11430
|
+
*/
|
|
11431
|
+
setWithHint(key, value, hint) {
|
|
11432
|
+
return this.setWithHintNode(key, value, hint) !== void 0;
|
|
11433
|
+
}
|
|
11434
|
+
/**
|
|
11435
|
+
* Insert or update a key/value (map mode) or key-only (set mode).
|
|
11436
|
+
*
|
|
11437
|
+
* This method is optimized for:
|
|
11438
|
+
* - monotonic inserts via min/max boundary fast paths
|
|
11439
|
+
* - updates via a single-pass search (no double walk)
|
|
11440
|
+
*
|
|
11441
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
10995
11442
|
*/
|
|
10996
11443
|
set(keyNodeOrEntry, value) {
|
|
11444
|
+
if (!this.isNode(keyNodeOrEntry)) {
|
|
11445
|
+
if (keyNodeOrEntry === null || keyNodeOrEntry === void 0) return false;
|
|
11446
|
+
if (this.isEntry(keyNodeOrEntry)) {
|
|
11447
|
+
const key = keyNodeOrEntry[0];
|
|
11448
|
+
if (key === null || key === void 0) return false;
|
|
11449
|
+
const nextValue = value != null ? value : keyNodeOrEntry[1];
|
|
11450
|
+
return this._setKV(key, nextValue);
|
|
11451
|
+
}
|
|
11452
|
+
return this._setKV(keyNodeOrEntry, value);
|
|
11453
|
+
}
|
|
10997
11454
|
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
|
10998
11455
|
if (!this.isRealNode(newNode)) return false;
|
|
10999
11456
|
const insertStatus = this._insert(newNode);
|
|
@@ -11015,19 +11472,23 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11015
11472
|
}
|
|
11016
11473
|
/**
|
|
11017
11474
|
* Delete a node by key/node/entry and rebalance as needed.
|
|
11018
|
-
* @remarks Time O(log n), Space O(1)
|
|
11019
|
-
* @param
|
|
11475
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11476
|
+
* @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
|
|
11020
11477
|
* @returns Array with deletion metadata (removed node, rebalancing hint if any).
|
|
11021
11478
|
*/
|
|
11022
|
-
delete(
|
|
11023
|
-
if (
|
|
11479
|
+
delete(keyNodeEntryRawOrPredicate) {
|
|
11480
|
+
if (keyNodeEntryRawOrPredicate === null) return [];
|
|
11024
11481
|
const results = [];
|
|
11025
11482
|
let nodeToDelete;
|
|
11026
|
-
if (this._isPredicate(
|
|
11027
|
-
else nodeToDelete = this.isRealNode(
|
|
11483
|
+
if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
|
|
11484
|
+
else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
|
|
11028
11485
|
if (!nodeToDelete) {
|
|
11029
11486
|
return results;
|
|
11030
11487
|
}
|
|
11488
|
+
const willDeleteMin = nodeToDelete === this._minNode;
|
|
11489
|
+
const willDeleteMax = nodeToDelete === this._maxNode;
|
|
11490
|
+
const nextMin = willDeleteMin ? this._successorOf(nodeToDelete) : void 0;
|
|
11491
|
+
const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : void 0;
|
|
11031
11492
|
let originalColor = nodeToDelete.color;
|
|
11032
11493
|
let replacementNode;
|
|
11033
11494
|
if (!this.isRealNode(nodeToDelete.left)) {
|
|
@@ -11066,6 +11527,19 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11066
11527
|
}
|
|
11067
11528
|
if (this._isMapMode) this._store.delete(nodeToDelete.key);
|
|
11068
11529
|
this._size--;
|
|
11530
|
+
if (this._size <= 0) {
|
|
11531
|
+
this._setMinCache(void 0);
|
|
11532
|
+
this._setMaxCache(void 0);
|
|
11533
|
+
} else {
|
|
11534
|
+
if (willDeleteMin) this._setMinCache(nextMin);
|
|
11535
|
+
if (willDeleteMax) this._setMaxCache(nextMax);
|
|
11536
|
+
if (!this._minNode || !this.isRealNode(this._minNode)) {
|
|
11537
|
+
this._setMinCache(this.isRealNode(this._root) ? this.getLeftMost((n) => n, this._root) : void 0);
|
|
11538
|
+
}
|
|
11539
|
+
if (!this._maxNode || !this.isRealNode(this._maxNode)) {
|
|
11540
|
+
this._setMaxCache(this.isRealNode(this._root) ? this.getRightMost((n) => n, this._root) : void 0);
|
|
11541
|
+
}
|
|
11542
|
+
}
|
|
11069
11543
|
if (originalColor === "BLACK") {
|
|
11070
11544
|
this._deleteFixup(replacementNode);
|
|
11071
11545
|
}
|
|
@@ -11074,7 +11548,7 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11074
11548
|
}
|
|
11075
11549
|
/**
|
|
11076
11550
|
* Transform entries into a like-kind red-black tree with possibly different key/value types.
|
|
11077
|
-
* @remarks Time O(n), Space O(n)
|
|
11551
|
+
* @remarks Time O(n) average, Space O(n)
|
|
11078
11552
|
* @template MK
|
|
11079
11553
|
* @template MV
|
|
11080
11554
|
* @template MR
|
|
@@ -11091,41 +11565,62 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11091
11565
|
}
|
|
11092
11566
|
return out;
|
|
11093
11567
|
}
|
|
11568
|
+
/**
|
|
11569
|
+
* (Internal) Create an empty instance of the same concrete tree type.
|
|
11570
|
+
* @remarks Time O(1) average, Space O(1)
|
|
11571
|
+
*/
|
|
11094
11572
|
_createInstance(options) {
|
|
11095
11573
|
const Ctor = this.constructor;
|
|
11096
11574
|
return new Ctor([], { ...this._snapshotOptions(), ...options != null ? options : {} });
|
|
11097
11575
|
}
|
|
11576
|
+
/**
|
|
11577
|
+
* (Internal) Create a like-kind tree (same concrete class) populated from an iterable.
|
|
11578
|
+
* @remarks Time O(m log m) average (m = iterable length), Space O(m)
|
|
11579
|
+
*/
|
|
11098
11580
|
_createLike(iter = [], options) {
|
|
11099
11581
|
const Ctor = this.constructor;
|
|
11100
11582
|
return new Ctor(iter, { ...this._snapshotOptions(), ...options != null ? options : {} });
|
|
11101
11583
|
}
|
|
11584
|
+
/**
|
|
11585
|
+
* (Internal) Set the root pointer and keep header.parent in sync.
|
|
11586
|
+
* @remarks Time O(1), Space O(1)
|
|
11587
|
+
*/
|
|
11102
11588
|
_setRoot(v) {
|
|
11589
|
+
const NIL = this.NIL;
|
|
11103
11590
|
if (v) {
|
|
11104
11591
|
v.parent = void 0;
|
|
11105
11592
|
}
|
|
11106
11593
|
this._root = v;
|
|
11594
|
+
this._header.parent = v != null ? v : NIL;
|
|
11107
11595
|
}
|
|
11596
|
+
/**
|
|
11597
|
+
* (Internal) Replace a node in place while preserving its color.
|
|
11598
|
+
* @remarks Time O(1) average, Space O(1)
|
|
11599
|
+
*/
|
|
11108
11600
|
_replaceNode(oldNode, newNode) {
|
|
11109
11601
|
newNode.color = oldNode.color;
|
|
11110
11602
|
return super._replaceNode(oldNode, newNode);
|
|
11111
11603
|
}
|
|
11112
11604
|
/**
|
|
11113
11605
|
* (Protected) Standard BST insert followed by red-black fix-up.
|
|
11114
|
-
* @remarks Time O(log n), Space O(1)
|
|
11606
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11115
11607
|
* @param node - Node to insert.
|
|
11116
11608
|
* @returns Status string: 'CREATED' or 'UPDATED'.
|
|
11117
11609
|
*/
|
|
11118
11610
|
_insert(node) {
|
|
11119
11611
|
var _a, _b, _c;
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11612
|
+
const NIL = this.NIL;
|
|
11613
|
+
const cmp = this._compare.bind(this);
|
|
11614
|
+
let current = (_a = this._header.parent) != null ? _a : NIL;
|
|
11615
|
+
let parent;
|
|
11616
|
+
let lastCompared = 0;
|
|
11617
|
+
while (current !== NIL) {
|
|
11123
11618
|
parent = current;
|
|
11124
|
-
|
|
11125
|
-
if (
|
|
11126
|
-
current = (_b = current.left) != null ? _b :
|
|
11127
|
-
} else if (
|
|
11128
|
-
current = (_c = current.right) != null ? _c :
|
|
11619
|
+
lastCompared = cmp(node.key, current.key);
|
|
11620
|
+
if (lastCompared < 0) {
|
|
11621
|
+
current = (_b = current.left) != null ? _b : NIL;
|
|
11622
|
+
} else if (lastCompared > 0) {
|
|
11623
|
+
current = (_c = current.right) != null ? _c : NIL;
|
|
11129
11624
|
} else {
|
|
11130
11625
|
this._replaceNode(current, node);
|
|
11131
11626
|
return "UPDATED";
|
|
@@ -11134,13 +11629,13 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11134
11629
|
node.parent = parent;
|
|
11135
11630
|
if (!parent) {
|
|
11136
11631
|
this._setRoot(node);
|
|
11137
|
-
} else if (
|
|
11632
|
+
} else if (lastCompared < 0) {
|
|
11138
11633
|
parent.left = node;
|
|
11139
11634
|
} else {
|
|
11140
11635
|
parent.right = node;
|
|
11141
11636
|
}
|
|
11142
|
-
node.left =
|
|
11143
|
-
node.right =
|
|
11637
|
+
node.left = NIL;
|
|
11638
|
+
node.right = NIL;
|
|
11144
11639
|
node.color = "RED";
|
|
11145
11640
|
this._insertFixup(node);
|
|
11146
11641
|
return "CREATED";
|
|
@@ -11166,56 +11661,66 @@ var _RedBlackTree = class _RedBlackTree extends BST {
|
|
|
11166
11661
|
}
|
|
11167
11662
|
/**
|
|
11168
11663
|
* (Protected) Restore red-black properties after insertion (recolor/rotate).
|
|
11169
|
-
* @remarks Time O(log n), Space O(1)
|
|
11664
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11170
11665
|
* @param z - Recently inserted node.
|
|
11171
11666
|
* @returns void
|
|
11172
11667
|
*/
|
|
11173
11668
|
_insertFixup(z) {
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11669
|
+
const leftRotate = this._leftRotate.bind(this);
|
|
11670
|
+
const rightRotate = this._rightRotate.bind(this);
|
|
11671
|
+
while (z) {
|
|
11672
|
+
const p = z.parent;
|
|
11673
|
+
if (!p || p.color !== "RED") break;
|
|
11674
|
+
const gp = p.parent;
|
|
11675
|
+
if (!gp) break;
|
|
11676
|
+
if (p === gp.left) {
|
|
11677
|
+
const y = gp.right;
|
|
11178
11678
|
if ((y == null ? void 0 : y.color) === "RED") {
|
|
11179
|
-
|
|
11679
|
+
p.color = "BLACK";
|
|
11180
11680
|
y.color = "BLACK";
|
|
11181
|
-
|
|
11182
|
-
z =
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11681
|
+
gp.color = "RED";
|
|
11682
|
+
z = gp;
|
|
11683
|
+
continue;
|
|
11684
|
+
}
|
|
11685
|
+
if (z === p.right) {
|
|
11686
|
+
z = p;
|
|
11687
|
+
leftRotate(z);
|
|
11688
|
+
}
|
|
11689
|
+
const p2 = z == null ? void 0 : z.parent;
|
|
11690
|
+
const gp2 = p2 == null ? void 0 : p2.parent;
|
|
11691
|
+
if (p2 && gp2) {
|
|
11692
|
+
p2.color = "BLACK";
|
|
11693
|
+
gp2.color = "RED";
|
|
11694
|
+
rightRotate(gp2);
|
|
11193
11695
|
}
|
|
11194
11696
|
} else {
|
|
11195
|
-
const y =
|
|
11697
|
+
const y = gp.left;
|
|
11196
11698
|
if ((y == null ? void 0 : y.color) === "RED") {
|
|
11197
|
-
|
|
11699
|
+
p.color = "BLACK";
|
|
11198
11700
|
y.color = "BLACK";
|
|
11199
|
-
|
|
11200
|
-
z =
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11701
|
+
gp.color = "RED";
|
|
11702
|
+
z = gp;
|
|
11703
|
+
continue;
|
|
11704
|
+
}
|
|
11705
|
+
if (z === p.left) {
|
|
11706
|
+
z = p;
|
|
11707
|
+
rightRotate(z);
|
|
11708
|
+
}
|
|
11709
|
+
const p2 = z == null ? void 0 : z.parent;
|
|
11710
|
+
const gp2 = p2 == null ? void 0 : p2.parent;
|
|
11711
|
+
if (p2 && gp2) {
|
|
11712
|
+
p2.color = "BLACK";
|
|
11713
|
+
gp2.color = "RED";
|
|
11714
|
+
leftRotate(gp2);
|
|
11211
11715
|
}
|
|
11212
11716
|
}
|
|
11717
|
+
break;
|
|
11213
11718
|
}
|
|
11214
11719
|
if (this.isRealNode(this._root)) this._root.color = "BLACK";
|
|
11215
11720
|
}
|
|
11216
11721
|
/**
|
|
11217
11722
|
* (Protected) Restore red-black properties after deletion (recolor/rotate).
|
|
11218
|
-
* @remarks Time O(log n), Space O(1)
|
|
11723
|
+
* @remarks Time O(log n) average, Space O(1)
|
|
11219
11724
|
* @param node - Child that replaced the deleted node (may be undefined).
|
|
11220
11725
|
* @returns void
|
|
11221
11726
|
*/
|
|
@@ -12118,16 +12623,16 @@ var _TreeCounter = class _TreeCounter extends RedBlackTree {
|
|
|
12118
12623
|
/**
|
|
12119
12624
|
* Delete a node (or decrement its count) and rebalance if needed.
|
|
12120
12625
|
* @remarks Time O(log N), Space O(1)
|
|
12121
|
-
* @param
|
|
12626
|
+
* @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node.
|
|
12122
12627
|
* @param [ignoreCount] - If true, remove the node regardless of its count.
|
|
12123
12628
|
* @returns Array of deletion results including deleted node and a rebalance hint when present.
|
|
12124
12629
|
*/
|
|
12125
|
-
delete(
|
|
12126
|
-
if (
|
|
12630
|
+
delete(keyNodeEntryRawOrPredicate, ignoreCount = false) {
|
|
12631
|
+
if (keyNodeEntryRawOrPredicate === null) return [];
|
|
12127
12632
|
const results = [];
|
|
12128
12633
|
let nodeToDelete;
|
|
12129
|
-
if (this._isPredicate(
|
|
12130
|
-
else nodeToDelete = this.isRealNode(
|
|
12634
|
+
if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
|
|
12635
|
+
else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
|
|
12131
12636
|
if (!nodeToDelete) {
|
|
12132
12637
|
return results;
|
|
12133
12638
|
}
|
|
@@ -12170,7 +12675,6 @@ var _TreeCounter = class _TreeCounter extends RedBlackTree {
|
|
|
12170
12675
|
if (ignoreCount || nodeToDelete.count <= 1) {
|
|
12171
12676
|
if (successor.right !== null) {
|
|
12172
12677
|
this._transplant(successor, successor.right);
|
|
12173
|
-
this._count -= nodeToDelete.count;
|
|
12174
12678
|
}
|
|
12175
12679
|
} else {
|
|
12176
12680
|
nodeToDelete.count--;
|
|
@@ -12273,6 +12777,11 @@ var _TreeCounter = class _TreeCounter extends RedBlackTree {
|
|
|
12273
12777
|
const out = this._createInstance();
|
|
12274
12778
|
this._clone(out);
|
|
12275
12779
|
out._count = this._count;
|
|
12780
|
+
for (const node of this.dfs((n) => n, "IN")) {
|
|
12781
|
+
if (!node) continue;
|
|
12782
|
+
const outNode = out.getNode(node.key);
|
|
12783
|
+
if (outNode) outNode.count = node.count;
|
|
12784
|
+
}
|
|
12276
12785
|
return out;
|
|
12277
12786
|
}
|
|
12278
12787
|
/**
|