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