data-structure-typed 2.2.7 → 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 +14 -3
- package/README_CN.md +119 -275
- package/benchmark/report.html +1 -1
- package/benchmark/report.json +20 -324
- package/dist/cjs/index.cjs +689 -182
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +693 -185
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +689 -182
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +693 -185
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/leetcode/avl-tree-counter.mjs +2957 -0
- package/dist/leetcode/avl-tree-multi-map.mjs +2889 -0
- package/dist/leetcode/avl-tree.mjs +2720 -0
- package/dist/leetcode/binary-tree.mjs +1594 -0
- package/dist/leetcode/bst.mjs +2398 -0
- package/dist/leetcode/deque.mjs +683 -0
- package/dist/leetcode/directed-graph.mjs +1733 -0
- package/dist/leetcode/doubly-linked-list.mjs +709 -0
- package/dist/leetcode/hash-map.mjs +493 -0
- package/dist/leetcode/heap.mjs +542 -0
- package/dist/leetcode/max-heap.mjs +375 -0
- package/dist/leetcode/max-priority-queue.mjs +383 -0
- package/dist/leetcode/min-heap.mjs +363 -0
- package/dist/leetcode/min-priority-queue.mjs +371 -0
- package/dist/leetcode/priority-queue.mjs +363 -0
- package/dist/leetcode/queue.mjs +943 -0
- package/dist/leetcode/red-black-tree.mjs +2765 -0
- package/dist/leetcode/singly-linked-list.mjs +754 -0
- package/dist/leetcode/stack.mjs +217 -0
- package/dist/leetcode/tree-counter.mjs +3039 -0
- package/dist/leetcode/tree-multi-map.mjs +2913 -0
- package/dist/leetcode/trie.mjs +413 -0
- package/dist/leetcode/undirected-graph.mjs +1650 -0
- package/dist/types/data-structures/base/linear-base.d.ts +6 -6
- package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +2 -2
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +10 -10
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +25 -27
- package/dist/types/data-structures/binary-tree/bst.d.ts +13 -12
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +151 -21
- package/dist/types/data-structures/binary-tree/tree-counter.d.ts +4 -4
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
- package/dist/types/interfaces/binary-tree.d.ts +1 -1
- package/dist/umd/data-structure-typed.js +689 -181
- 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 +50 -172
- package/src/data-structures/base/linear-base.ts +2 -12
- package/src/data-structures/binary-tree/avl-tree-counter.ts +6 -6
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +13 -13
- package/src/data-structures/binary-tree/avl-tree.ts +15 -15
- package/src/data-structures/binary-tree/binary-tree.ts +57 -60
- package/src/data-structures/binary-tree/bst.ts +100 -26
- package/src/data-structures/binary-tree/red-black-tree.ts +586 -76
- package/src/data-structures/binary-tree/tree-counter.ts +25 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +13 -13
- package/src/data-structures/queue/deque.ts +10 -0
- package/src/interfaces/binary-tree.ts +1 -1
- package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +1 -2
- 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-counter.test.ts +30 -30
- 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-multi-map.test.ts +46 -46
- 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/avl-tree.test.ts +43 -43
- 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/binary-tree.test.ts +151 -151
- 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 +124 -154
- package/test/unit/data-structures/binary-tree/overall.test.ts +20 -20
- 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.test.ts +141 -141
- 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 +41 -39
- 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/binary-tree/tree-multi-map.test.ts +145 -145
- 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/tsup.config.js +50 -21
- package/tsup.umd.config.js +29 -0
- package/tsup.node.config.js +0 -83
package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree setWithHintNode mapMode defined-value branches', () => {
|
|
4
|
+
it('direct attach left/right with defined values uses store.set branches', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>(); // mapMode default
|
|
6
|
+
t.set(10, 10);
|
|
7
|
+
const h10 = t.getNode(10)!;
|
|
8
|
+
|
|
9
|
+
const n5 = t.setWithHintNode(5, 5, h10);
|
|
10
|
+
expect(n5?.key).toBe(5);
|
|
11
|
+
expect((t as any)._store.get(5)).toBe(5);
|
|
12
|
+
|
|
13
|
+
const n15 = t.setWithHintNode(15, 15, h10);
|
|
14
|
+
expect(n15?.key).toBe(15);
|
|
15
|
+
expect((t as any)._store.get(15)).toBe(15);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('pred.right and succ.left attach with defined values uses store.set branches', () => {
|
|
19
|
+
const t = new RedBlackTree<number, number>();
|
|
20
|
+
t.set(10, 10);
|
|
21
|
+
const h10 = t.getNode(10)!;
|
|
22
|
+
|
|
23
|
+
// Ensure left is real so we take pred path.
|
|
24
|
+
t.setWithHintNode(5, 5, h10);
|
|
25
|
+
const n7 = t.setWithHintNode(7, 7, h10);
|
|
26
|
+
expect(n7?.key).toBe(7);
|
|
27
|
+
expect((t as any)._store.get(7)).toBe(7);
|
|
28
|
+
|
|
29
|
+
// Ensure right is real so we take succ path.
|
|
30
|
+
t.setWithHintNode(15, 15, h10);
|
|
31
|
+
const n12 = t.setWithHintNode(12, 12, h10);
|
|
32
|
+
expect(n12?.key).toBe(12);
|
|
33
|
+
expect((t as any)._store.get(12)).toBe(12);
|
|
34
|
+
});
|
|
35
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree setWithHintNode mapMode undefined-value branches', () => {
|
|
4
|
+
it('direct attach left/right with undefined value hits _setValue branches (no store entry)', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>(); // mapMode default
|
|
6
|
+
t.set(10, 10);
|
|
7
|
+
const h10 = t.getNode(10)!;
|
|
8
|
+
|
|
9
|
+
const n5 = t.setWithHintNode(5, undefined as any, h10);
|
|
10
|
+
expect(n5?.key).toBe(5);
|
|
11
|
+
expect(t.getNode(5)).toBeTruthy();
|
|
12
|
+
expect((t as any)._store.has(5)).toBe(false);
|
|
13
|
+
|
|
14
|
+
const n15 = t.setWithHintNode(15, undefined as any, h10);
|
|
15
|
+
expect(n15?.key).toBe(15);
|
|
16
|
+
expect(t.getNode(15)).toBeTruthy();
|
|
17
|
+
expect((t as any)._store.has(15)).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('pred.right and succ.left attach with undefined value hit _setValue branches', () => {
|
|
21
|
+
const t = new RedBlackTree<number, number>();
|
|
22
|
+
t.set(10, 10);
|
|
23
|
+
const h10 = t.getNode(10)!;
|
|
24
|
+
|
|
25
|
+
// Ensure left is real so we take the pred path.
|
|
26
|
+
t.setWithHintNode(5, 5, h10);
|
|
27
|
+
|
|
28
|
+
// Insert between pred(5) and hint(10): attaches as pred.right.
|
|
29
|
+
const n7 = t.setWithHintNode(7, undefined as any, h10);
|
|
30
|
+
expect(n7?.key).toBe(7);
|
|
31
|
+
expect(t.getNode(7)).toBeTruthy();
|
|
32
|
+
expect((t as any)._store.has(7)).toBe(false);
|
|
33
|
+
|
|
34
|
+
// Ensure right is real so we take the succ path.
|
|
35
|
+
t.setWithHintNode(15, 15, h10);
|
|
36
|
+
|
|
37
|
+
// Insert between hint(10) and succ(15): attaches as succ.left.
|
|
38
|
+
const n12 = t.setWithHintNode(12, undefined as any, h10);
|
|
39
|
+
expect(n12?.key).toBe(12);
|
|
40
|
+
expect(t.getNode(12)).toBeTruthy();
|
|
41
|
+
expect((t as any)._store.has(12)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
class RBTWithBadCreate extends RedBlackTree<number, number> {
|
|
4
|
+
override createNode(key: number, value?: number): any {
|
|
5
|
+
// Simulate unexpected internal failure so setWithHintNode guard branches are covered.
|
|
6
|
+
// Keys chosen to avoid falling back to _setKVNode boundary attach (which assumes createNode always succeeds).
|
|
7
|
+
if (key === 7 || key === 6 || key === 17 || key === 14) return undefined;
|
|
8
|
+
return super.createNode(key, value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('RedBlackTree setWithHintNode more branch coverage', () => {
|
|
13
|
+
it('covers c0===0 update (set mode + mapMode undefined/value)', () => {
|
|
14
|
+
// set mode
|
|
15
|
+
const s = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
16
|
+
s.set(10, 1);
|
|
17
|
+
const h10 = s.getNode(10)!;
|
|
18
|
+
s.setWithHintNode(10, 2, h10);
|
|
19
|
+
expect(s.getNode(10)?.value).toBe(2);
|
|
20
|
+
|
|
21
|
+
// mapMode: value !== undefined uses store.set; value === undefined uses _setValue path.
|
|
22
|
+
const m = new RedBlackTree<number, number>();
|
|
23
|
+
m.set(10, 1);
|
|
24
|
+
const mh10 = m.getNode(10)!;
|
|
25
|
+
m.setWithHintNode(10, 3, mh10);
|
|
26
|
+
expect(m.get(10)).toBe(3);
|
|
27
|
+
|
|
28
|
+
// undefined update should preserve existing value (existing semantics).
|
|
29
|
+
m.setWithHintNode(10, undefined as any, mh10);
|
|
30
|
+
expect(m.get(10)).toBe(3);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('covers c0<0: direct attach to hint.left, pred fallback, and pred.right attach', () => {
|
|
34
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
35
|
+
|
|
36
|
+
// direct attach: hint.left is empty
|
|
37
|
+
t.set(10, 10);
|
|
38
|
+
const h10 = t.getNode(10)!;
|
|
39
|
+
const n5 = t.setWithHintNode(5, 5, h10)!;
|
|
40
|
+
expect(n5.key).toBe(5);
|
|
41
|
+
|
|
42
|
+
// pred fallback: key equals predecessor (cmp(pred.key,key) >= 0)
|
|
43
|
+
t.setWithHintNode(5, 55, h10);
|
|
44
|
+
expect(t.getNode(5)?.value).toBe(55);
|
|
45
|
+
|
|
46
|
+
// pred.right attach: insert between pred(5) and hint(10)
|
|
47
|
+
const n7 = t.setWithHintNode(7, 7, h10)!;
|
|
48
|
+
expect(n7.key).toBe(7);
|
|
49
|
+
expect(t.getNode(7)?.value).toBe(7);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('covers c0>0: direct attach to hint.right, succ fallback, and succ.left attach', () => {
|
|
53
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
54
|
+
|
|
55
|
+
// direct attach: hint.right is empty
|
|
56
|
+
t.set(10, 10);
|
|
57
|
+
const h10 = t.getNode(10)!;
|
|
58
|
+
const n15 = t.setWithHintNode(15, 15, h10)!;
|
|
59
|
+
expect(n15.key).toBe(15);
|
|
60
|
+
|
|
61
|
+
// succ fallback: key equals successor (cmp(succ.key,key) <= 0)
|
|
62
|
+
t.setWithHintNode(15, 155, h10);
|
|
63
|
+
expect(t.getNode(15)?.value).toBe(155);
|
|
64
|
+
|
|
65
|
+
// succ.left attach: insert between hint(10) and succ(15)
|
|
66
|
+
const n12 = t.setWithHintNode(12, 12, h10)!;
|
|
67
|
+
expect(n12.key).toBe(12);
|
|
68
|
+
expect(t.getNode(12)?.value).toBe(12);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('covers guard branches where createNode unexpectedly fails (returns undefined)', () => {
|
|
72
|
+
const t = new RBTWithBadCreate([], { isMapMode: false });
|
|
73
|
+
t.set(10, 10);
|
|
74
|
+
const h10 = t.getNode(10)!;
|
|
75
|
+
|
|
76
|
+
// c0<0 direct attach guard (newNode not real)
|
|
77
|
+
expect(t.setWithHintNode(7, 7, h10)).toBeUndefined();
|
|
78
|
+
|
|
79
|
+
// ensure left is real so we go pred-right attach guard
|
|
80
|
+
t.setWithHintNode(5, 5, h10);
|
|
81
|
+
expect(t.setWithHintNode(6, 6, h10)).toBeUndefined();
|
|
82
|
+
|
|
83
|
+
// c0>0 direct attach guard (hint.right is empty)
|
|
84
|
+
expect(t.setWithHintNode(17, 17, h10)).toBeUndefined();
|
|
85
|
+
|
|
86
|
+
// ensure right is real so we go succ-left attach guard (key between hint and succ)
|
|
87
|
+
t.setWithHintNode(15, 15, h10);
|
|
88
|
+
expect(t.setWithHintNode(14, 14, h10)).toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('covers setWithHintNode fallback when hint is not real', () => {
|
|
92
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
93
|
+
t.set(1, 1);
|
|
94
|
+
|
|
95
|
+
// Passing NIL should be treated as not-real and fallback to normal set.
|
|
96
|
+
const out = t.setWithHintNode(2, 2, t.NIL as any);
|
|
97
|
+
expect(out?.key).toBe(2);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree hint/update coverage', () => {
|
|
4
|
+
it('mapMode update fast-path keeps size and node reference stable', () => {
|
|
5
|
+
const t = new RedBlackTree<number, string>([], { isMapMode: true });
|
|
6
|
+
t.set(1, 'a');
|
|
7
|
+
const n1 = t.getNode(1);
|
|
8
|
+
expect(n1).toBeTruthy();
|
|
9
|
+
|
|
10
|
+
t.set(1, 'b');
|
|
11
|
+
const n2 = t.getNode(1);
|
|
12
|
+
|
|
13
|
+
expect(t.size).toBe(1);
|
|
14
|
+
expect(t.get(1)).toBe('b');
|
|
15
|
+
expect(n2).toBe(n1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('setWithHintNode covers: no hint -> fallback, c0==0 update, and left/right attach branches', () => {
|
|
19
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
20
|
+
for (const k of [10, 5, 15]) t.set(k, k);
|
|
21
|
+
|
|
22
|
+
// no hint -> fallback
|
|
23
|
+
const n20 = t.setWithHintNode(20, 20, undefined);
|
|
24
|
+
expect(n20?.key).toBe(20);
|
|
25
|
+
|
|
26
|
+
// c0 == 0 update
|
|
27
|
+
const hint10 = t.getNode(10)!;
|
|
28
|
+
const updated10 = t.setWithHintNode(10, 999, hint10);
|
|
29
|
+
expect(updated10).toBe(hint10);
|
|
30
|
+
expect(t.get(10)).toBe(999);
|
|
31
|
+
|
|
32
|
+
// left attach (hint.left is empty)
|
|
33
|
+
const hint5 = t.getNode(5)!;
|
|
34
|
+
const n2 = t.setWithHintNode(2, 2, hint5);
|
|
35
|
+
expect(n2?.parent?.key).toBe(5);
|
|
36
|
+
expect(n2?.key).toBe(2);
|
|
37
|
+
|
|
38
|
+
// predecessor-right attach (hint.left exists)
|
|
39
|
+
// key=7 is <10, pred(10)=5 and pred.right is empty -> attach there.
|
|
40
|
+
const n7 = t.setWithHintNode(7, 7, hint10);
|
|
41
|
+
expect(n7?.key).toBe(7);
|
|
42
|
+
expect(n7?.parent?.key).toBe(5);
|
|
43
|
+
|
|
44
|
+
// successor-left attach (hint.right exists)
|
|
45
|
+
// key=13 is >10, succ(10)=15 and succ.left is empty -> attach there.
|
|
46
|
+
const n13 = t.setWithHintNode(13, 13, hint10);
|
|
47
|
+
expect(n13?.key).toBe(13);
|
|
48
|
+
expect(n13?.parent?.key).toBe(15);
|
|
49
|
+
|
|
50
|
+
// succ.key <= key fallback branch
|
|
51
|
+
const n30 = t.setWithHintNode(30, 30, hint10);
|
|
52
|
+
expect(n30?.key).toBe(30);
|
|
53
|
+
expect(t.getNode(30)).toBeTruthy();
|
|
54
|
+
|
|
55
|
+
// pred.key >= key fallback branch
|
|
56
|
+
const n4 = t.setWithHintNode(4, 4, hint10);
|
|
57
|
+
expect(n4?.key).toBe(4);
|
|
58
|
+
expect(t.getNode(4)).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree insert cache nullish coverage', () => {
|
|
4
|
+
it('normal insert repairs nullish header._left/_right via (hMin===NIL || hMax===NIL) fast-path', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
6
|
+
|
|
7
|
+
// Build a non-empty tree so header.parent/root is real.
|
|
8
|
+
for (const k of [10, 20, 30]) t.set(k, k);
|
|
9
|
+
|
|
10
|
+
// Corrupt caches so boundary fast-path is skipped (minN becomes NIL via ??) and
|
|
11
|
+
// post-insert cache maintenance sees hMin/hMax as NIL.
|
|
12
|
+
(t as any)._header._left = undefined;
|
|
13
|
+
(t as any)._header._right = undefined;
|
|
14
|
+
|
|
15
|
+
t.set(25, 25);
|
|
16
|
+
|
|
17
|
+
// After insertion, cache maintenance should have initialized both caches.
|
|
18
|
+
expect((t as any)._header._left.key).toBe(25);
|
|
19
|
+
expect((t as any)._header._right.key).toBe(25);
|
|
20
|
+
|
|
21
|
+
// Repair caches to avoid polluting subsequent tests/users.
|
|
22
|
+
const root = (t as any)._root;
|
|
23
|
+
(t as any)._setMinCache(t.isRealNode(root) ? t.getLeftMost((n: any) => n, root) : undefined);
|
|
24
|
+
(t as any)._setMaxCache(t.isRealNode(root) ? t.getRightMost((n: any) => n, root) : undefined);
|
|
25
|
+
|
|
26
|
+
expect((t as any)._header._left.key).toBe(10);
|
|
27
|
+
expect((t as any)._header._right.key).toBe(30);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree _insert header.parent ?? NIL coverage', () => {
|
|
4
|
+
it('covers _insert with header.parent undefined (current starts at NIL)', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
6
|
+
|
|
7
|
+
// Force the _insert walk to start from NIL.
|
|
8
|
+
(t as any)._header.parent = undefined;
|
|
9
|
+
(t as any)._root = t.NIL;
|
|
10
|
+
|
|
11
|
+
const n = new RedBlackTreeNode<number, number>(10, 10, 'BLACK');
|
|
12
|
+
expect(t.set(n, 10)).toBe(true);
|
|
13
|
+
|
|
14
|
+
// Should have established a real root via _setRoot.
|
|
15
|
+
expect(t.getNode(10)?.key).toBe(10);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree internal walk coverage', () => {
|
|
4
|
+
it('_findNodeByKey covers header.parent ?? NIL and child ?? NIL branches', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
6
|
+
t.set(10, 10);
|
|
7
|
+
|
|
8
|
+
// header.parent ?? NIL (set to undefined)
|
|
9
|
+
(t as any)._header.parent = undefined;
|
|
10
|
+
expect((t as any)._findNodeByKey(10)).toBeUndefined();
|
|
11
|
+
|
|
12
|
+
// Restore canonical root pointer.
|
|
13
|
+
(t as any)._header.parent = (t as any)._root;
|
|
14
|
+
|
|
15
|
+
// Force missing children to exercise `cur.left ?? NIL` and `cur.right ?? NIL`.
|
|
16
|
+
const root = (t as any)._header.parent;
|
|
17
|
+
root._left = undefined;
|
|
18
|
+
root._right = undefined;
|
|
19
|
+
|
|
20
|
+
expect((t as any)._findNodeByKey(5)).toBeUndefined();
|
|
21
|
+
expect((t as any)._findNodeByKey(15)).toBeUndefined();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('_insert covers current.left/right ?? NIL branches when root child pointers are undefined', () => {
|
|
25
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
26
|
+
t.set(10, 10);
|
|
27
|
+
|
|
28
|
+
const root = (t as any)._header.parent;
|
|
29
|
+
|
|
30
|
+
// Insert left with root._left undefined
|
|
31
|
+
root._left = undefined;
|
|
32
|
+
const n5 = new RedBlackTreeNode<number, number>(5, 5, 'BLACK');
|
|
33
|
+
expect(t.set(n5)).toBe(true);
|
|
34
|
+
|
|
35
|
+
// Reset to single root
|
|
36
|
+
t.clear();
|
|
37
|
+
t.set(10, 10);
|
|
38
|
+
|
|
39
|
+
const root2 = (t as any)._header.parent;
|
|
40
|
+
// Insert right with root._right undefined
|
|
41
|
+
root2._right = undefined;
|
|
42
|
+
const n15 = new RedBlackTreeNode<number, number>(15, 15, 'BLACK');
|
|
43
|
+
expect(t.set(n15)).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('_setKVNode covers header._left ?? NIL when header._left is undefined (no boundary fast path)', () => {
|
|
47
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
48
|
+
t.set(10, 10);
|
|
49
|
+
|
|
50
|
+
// Corrupt cache pointer so `header._left ?? NIL` uses NIL.
|
|
51
|
+
(t as any)._header._left = undefined;
|
|
52
|
+
|
|
53
|
+
// Should still insert normally.
|
|
54
|
+
expect(t.set(5, 5)).toBe(true);
|
|
55
|
+
expect(t.getNode(5)).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Regression tests for RedBlackTree min/max cache + boundary fast paths.
|
|
5
|
+
* Focus: correctness when inserting monotonic keys and deleting boundary nodes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
describe('RedBlackTree min/max cache regression', () => {
|
|
9
|
+
it('should keep min/max correct across increasing inserts and boundary deletes', () => {
|
|
10
|
+
const rb = new RedBlackTree<number, number>();
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < 1000; i++) rb.set(i, i);
|
|
13
|
+
|
|
14
|
+
// delete min repeatedly
|
|
15
|
+
for (let i = 0; i < 250; i++) {
|
|
16
|
+
rb.delete(i);
|
|
17
|
+
const min = rb.getLeftMost(n => n, rb.root);
|
|
18
|
+
expect(min?.key).toBe(i + 1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// delete max repeatedly
|
|
22
|
+
for (let i = 999; i >= 750; i--) {
|
|
23
|
+
rb.delete(i);
|
|
24
|
+
const max = rb.getRightMost(n => n, rb.root);
|
|
25
|
+
expect(max?.key).toBe(i - 1);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should reset min/max on clear and after deleting to empty', () => {
|
|
30
|
+
const rb = new RedBlackTree<number, number>();
|
|
31
|
+
rb.set(1, 1);
|
|
32
|
+
rb.set(2, 2);
|
|
33
|
+
|
|
34
|
+
rb.clear();
|
|
35
|
+
expect(rb.size).toBe(0);
|
|
36
|
+
expect(rb.getLeftMost(n => n, rb.root)).toBe(undefined);
|
|
37
|
+
expect(rb.getRightMost(n => n, rb.root)).toBe(undefined);
|
|
38
|
+
|
|
39
|
+
rb.set(10, 10);
|
|
40
|
+
rb.delete(10);
|
|
41
|
+
expect(rb.size).toBe(0);
|
|
42
|
+
expect(rb.getLeftMost(n => n, rb.root)).toBe(undefined);
|
|
43
|
+
expect(rb.getRightMost(n => n, rb.root)).toBe(undefined);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should keep min/max correct across decreasing inserts and boundary deletes', () => {
|
|
47
|
+
const rb = new RedBlackTree<number, number>();
|
|
48
|
+
|
|
49
|
+
for (let i = 1000; i >= 1; i--) rb.set(i, i);
|
|
50
|
+
|
|
51
|
+
// delete min repeatedly
|
|
52
|
+
for (let k = 1; k <= 250; k++) {
|
|
53
|
+
rb.delete(k);
|
|
54
|
+
const min = rb.getLeftMost(n => n, rb.root);
|
|
55
|
+
expect(min?.key).toBe(k + 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// delete max repeatedly
|
|
59
|
+
for (let k = 1000; k >= 751; k--) {
|
|
60
|
+
rb.delete(k);
|
|
61
|
+
const max = rb.getRightMost(n => n, rb.root);
|
|
62
|
+
expect(max?.key).toBe(k - 1);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree misc input coverage', () => {
|
|
4
|
+
it('delete(null) returns [] and does not throw', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
6
|
+
t.set(1, 1);
|
|
7
|
+
expect(t.delete(null as any)).toEqual([]);
|
|
8
|
+
expect(t.size).toBe(1);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('delete(undefined) returns [] and does not throw', () => {
|
|
12
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
13
|
+
t.set(1, 1);
|
|
14
|
+
expect(t.delete(undefined as any)).toEqual([]);
|
|
15
|
+
expect(t.size).toBe(1);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree remaining reachable branches (coverage)', () => {
|
|
4
|
+
it('mapMode updates existing MAX key with defined value via boundary cMax===0 path inside _setKVNode (covers store.set branch)', () => {
|
|
5
|
+
const t = new RedBlackTree<number, string>([], { isMapMode: true });
|
|
6
|
+
t.set(1, 'a');
|
|
7
|
+
t.set(2, 'b');
|
|
8
|
+
|
|
9
|
+
// Bypass _setKV store.has fast-path by corrupting the store (node exists but store.has(key) is false).
|
|
10
|
+
(t as any)._store.delete(2);
|
|
11
|
+
|
|
12
|
+
// key==max => boundary cMax===0 update in _setKVNode
|
|
13
|
+
t.set(2, 'bb');
|
|
14
|
+
expect(t.get(2)).toBe('bb');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('mapMode updates existing interior key with defined value via normal search update branch inside _setKVNode', () => {
|
|
18
|
+
const t = new RedBlackTree<number, string>([], { isMapMode: true });
|
|
19
|
+
t.set(10, 'x');
|
|
20
|
+
t.set(5, 'a');
|
|
21
|
+
t.set(15, 'z');
|
|
22
|
+
|
|
23
|
+
// Bypass _setKV store.has fast-path for this key.
|
|
24
|
+
(t as any)._store.delete(10);
|
|
25
|
+
|
|
26
|
+
// Update a non-min/non-max key to avoid boundary min/max equality early returns.
|
|
27
|
+
t.set(10, 'xx');
|
|
28
|
+
expect(t.get(10)).toBe('xx');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('normal-path search uses right ?? NIL fallback when a node child pointer is undefined', () => {
|
|
32
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
33
|
+
t.set(10, 10);
|
|
34
|
+
t.set(5, 5);
|
|
35
|
+
|
|
36
|
+
const n5 = t.getNode(5)!;
|
|
37
|
+
|
|
38
|
+
// Corrupt: right pointer becomes undefined (instead of NIL).
|
|
39
|
+
// This should exercise `current = current.right ?? NIL` fallback.
|
|
40
|
+
(n5 as any).right = undefined;
|
|
41
|
+
|
|
42
|
+
t.set(7, 7);
|
|
43
|
+
expect(t.get(7)).toBe(7);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('setWithHintNode cache maintenance evaluates compare operands in all 4 fast-attach variants', () => {
|
|
47
|
+
// (1) c0 < 0, direct attach to hint.left
|
|
48
|
+
{
|
|
49
|
+
const t = new RedBlackTree<number, number>();
|
|
50
|
+
t.set(10, 10);
|
|
51
|
+
t.set(20, 20);
|
|
52
|
+
// Ensure caches are real nodes (not NIL)
|
|
53
|
+
(t as any)._header._left = t.getNode(10);
|
|
54
|
+
(t as any)._header._right = t.getNode(20);
|
|
55
|
+
|
|
56
|
+
const hint = t.getNode(20)!;
|
|
57
|
+
const n = t.setWithHintNode(15, 15, hint)!;
|
|
58
|
+
expect(n.key).toBe(15);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// (2) c0 < 0, attach as right child of predecessor
|
|
62
|
+
{
|
|
63
|
+
const t = new RedBlackTree<number, number>();
|
|
64
|
+
t.set(10, 10);
|
|
65
|
+
t.set(20, 20);
|
|
66
|
+
// Make hint.left real so direct attach is skipped
|
|
67
|
+
t.set(5, 5);
|
|
68
|
+
(t as any)._header._left = t.getNode(5);
|
|
69
|
+
(t as any)._header._right = t.getNode(20);
|
|
70
|
+
|
|
71
|
+
const hint = t.getNode(20)!;
|
|
72
|
+
const n = t.setWithHintNode(15, 15, hint)!;
|
|
73
|
+
expect(n.key).toBe(15);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// (3) c0 > 0, direct attach to hint.right
|
|
77
|
+
{
|
|
78
|
+
const t = new RedBlackTree<number, number>();
|
|
79
|
+
t.set(10, 10);
|
|
80
|
+
t.set(20, 20);
|
|
81
|
+
(t as any)._header._left = t.getNode(10);
|
|
82
|
+
(t as any)._header._right = t.getNode(20);
|
|
83
|
+
|
|
84
|
+
const hint = t.getNode(20)!;
|
|
85
|
+
const n = t.setWithHintNode(30, 30, hint)!;
|
|
86
|
+
expect(n.key).toBe(30);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// (4) c0 > 0, attach as left child of successor
|
|
90
|
+
{
|
|
91
|
+
const t = new RedBlackTree<number, number>();
|
|
92
|
+
t.set(10, 10);
|
|
93
|
+
t.set(30, 30);
|
|
94
|
+
t.set(20, 20);
|
|
95
|
+
// ensure hint.right is real (30) so direct attach is skipped
|
|
96
|
+
(t as any)._header._left = t.getNode(10);
|
|
97
|
+
(t as any)._header._right = t.getNode(30);
|
|
98
|
+
|
|
99
|
+
const hint = t.getNode(20)!;
|
|
100
|
+
const n = t.setWithHintNode(25, 25, hint)!;
|
|
101
|
+
expect(n.key).toBe(25);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('_leftRotate and _rightRotate early-return when pivot or required child is missing', () => {
|
|
106
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
107
|
+
|
|
108
|
+
// undefined pivot
|
|
109
|
+
(t as any)._leftRotate(undefined);
|
|
110
|
+
(t as any)._rightRotate(undefined);
|
|
111
|
+
|
|
112
|
+
// pivot exists but missing required child
|
|
113
|
+
const x = new RedBlackTreeNode<number, number>(1);
|
|
114
|
+
(x as any).right = undefined;
|
|
115
|
+
const y = new RedBlackTreeNode<number, number>(2);
|
|
116
|
+
(y as any).left = undefined;
|
|
117
|
+
|
|
118
|
+
(t as any)._leftRotate(x);
|
|
119
|
+
(t as any)._rightRotate(y);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree additional reachable branch coverage (batch 3)', () => {
|
|
4
|
+
it('insertion cache: hits parent===hMax and parent===hMin else-if branches', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>();
|
|
6
|
+
|
|
7
|
+
t.set(2, 2);
|
|
8
|
+
// new max: parent should be current max
|
|
9
|
+
t.set(3, 3);
|
|
10
|
+
|
|
11
|
+
t.clear();
|
|
12
|
+
|
|
13
|
+
t.set(2, 2);
|
|
14
|
+
// new min: parent should be current min
|
|
15
|
+
t.set(1, 1);
|
|
16
|
+
|
|
17
|
+
// Sanity: min/max nodes exist and are ordered.
|
|
18
|
+
expect(t.getLeftMost((n: any) => n)?.key).toBe(1);
|
|
19
|
+
expect(t.getRightMost((n: any) => n)?.key).toBe(2);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('setWithHintNode: executes min/max cache logical-expr second operands across all 4 ultra-fast attach variants', () => {
|
|
23
|
+
const t = new RedBlackTree<number, number>();
|
|
24
|
+
|
|
25
|
+
// Seed non-empty tree so hMin/hMax are real and `hMin===NIL || compare(...)` evaluates RHS.
|
|
26
|
+
t.setMany([
|
|
27
|
+
[10, 10],
|
|
28
|
+
[20, 20],
|
|
29
|
+
[30, 30]
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const n10 = t.getNode(10)!;
|
|
33
|
+
const n20 = t.getNode(20)!;
|
|
34
|
+
const n30 = t.getNode(30)!;
|
|
35
|
+
|
|
36
|
+
// 1) direct attach as left of hint (new global min)
|
|
37
|
+
const n5 = t.setWithHintNode(5, 5, n10);
|
|
38
|
+
expect(n5?.key).toBe(5);
|
|
39
|
+
|
|
40
|
+
// 2) attach as right of predecessor
|
|
41
|
+
const n15 = t.setWithHintNode(15, 15, n20);
|
|
42
|
+
expect(n15?.key).toBe(15);
|
|
43
|
+
|
|
44
|
+
// 3) direct attach as right of hint (new global max)
|
|
45
|
+
const n40 = t.setWithHintNode(40, 40, n30);
|
|
46
|
+
expect(n40?.key).toBe(40);
|
|
47
|
+
|
|
48
|
+
// 4) attach as left of successor
|
|
49
|
+
const n25 = t.setWithHintNode(25, 25, n20);
|
|
50
|
+
expect(n25?.key).toBe(25);
|
|
51
|
+
|
|
52
|
+
expect(t.getLeftMost((n: any) => n)?.key).toBe(5);
|
|
53
|
+
expect(t.getRightMost((n: any) => n)?.key).toBe(40);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree additional reachable branch coverage (batch 4)', () => {
|
|
4
|
+
it('setWithHintNode: covers header._left/_right nullish-coalescing RHS (?? NIL) in all 4 ultra-fast attach variants', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>();
|
|
6
|
+
|
|
7
|
+
t.setMany([
|
|
8
|
+
[10, 10],
|
|
9
|
+
[20, 20],
|
|
10
|
+
[30, 30]
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
const n10 = t.getNode(10)!;
|
|
14
|
+
const n20 = t.getNode(20)!;
|
|
15
|
+
const n30 = t.getNode(30)!;
|
|
16
|
+
|
|
17
|
+
const clearHeaderMinMaxToUndefined = () => {
|
|
18
|
+
// Simulate a stale/partial cache state. This is a realistic “repair” scenario:
|
|
19
|
+
// the code uses `?? NIL` to tolerate undefined here.
|
|
20
|
+
(t as any)._header._left = undefined;
|
|
21
|
+
(t as any)._header._right = undefined;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// 1) direct attach as left of hint
|
|
25
|
+
clearHeaderMinMaxToUndefined();
|
|
26
|
+
expect(t.setWithHintNode(5, 5, n10)?.key).toBe(5);
|
|
27
|
+
|
|
28
|
+
// 2) attach as right of predecessor
|
|
29
|
+
clearHeaderMinMaxToUndefined();
|
|
30
|
+
expect(t.setWithHintNode(15, 15, n20)?.key).toBe(15);
|
|
31
|
+
|
|
32
|
+
// 3) direct attach as right of hint
|
|
33
|
+
clearHeaderMinMaxToUndefined();
|
|
34
|
+
expect(t.setWithHintNode(40, 40, n30)?.key).toBe(40);
|
|
35
|
+
|
|
36
|
+
// 4) attach as left of successor
|
|
37
|
+
clearHeaderMinMaxToUndefined();
|
|
38
|
+
expect(t.setWithHintNode(25, 25, n20)?.key).toBe(25);
|
|
39
|
+
|
|
40
|
+
// Sanity: tree still orders correctly.
|
|
41
|
+
expect(t.getLeftMost(n => n)?.key).toBe(5);
|
|
42
|
+
expect(t.getRightMost(n => n)?.key).toBe(40);
|
|
43
|
+
});
|
|
44
|
+
});
|