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