data-structure-typed 2.0.4 → 2.1.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/CHANGELOG.md +3 -1
- package/COMMANDS.md +17 -0
- package/README.md +11 -11
- package/benchmark/report.html +13 -77
- package/benchmark/report.json +158 -190
- package/dist/cjs/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/cjs/data-structures/base/iterable-element-base.js +149 -107
- package/dist/cjs/data-structures/base/iterable-element-base.js.map +1 -1
- package/dist/cjs/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/cjs/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/cjs/data-structures/base/iterable-entry-base.js.map +1 -1
- package/dist/cjs/data-structures/base/linear-base.d.ts +250 -192
- package/dist/cjs/data-structures/base/linear-base.js +137 -274
- package/dist/cjs/data-structures/base/linear-base.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/cjs/data-structures/binary-tree/avl-tree-counter.js +171 -205
- package/dist/cjs/data-structures/binary-tree/avl-tree-counter.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
- package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/cjs/data-structures/binary-tree/avl-tree.js +208 -195
- package/dist/cjs/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/cjs/data-structures/binary-tree/binary-tree.js +608 -875
- package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/cjs/data-structures/binary-tree/bst.js +505 -481
- package/dist/cjs/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/cjs/data-structures/binary-tree/red-black-tree.js +114 -209
- package/dist/cjs/data-structures/binary-tree/red-black-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/cjs/data-structures/binary-tree/tree-counter.js +172 -203
- package/dist/cjs/data-structures/binary-tree/tree-counter.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +105 -85
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
- package/dist/cjs/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/cjs/data-structures/graph/abstract-graph.js +267 -237
- package/dist/cjs/data-structures/graph/abstract-graph.js.map +1 -1
- package/dist/cjs/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/cjs/data-structures/graph/directed-graph.js +146 -233
- package/dist/cjs/data-structures/graph/directed-graph.js.map +1 -1
- package/dist/cjs/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/cjs/data-structures/graph/map-graph.js +56 -59
- package/dist/cjs/data-structures/graph/map-graph.js.map +1 -1
- package/dist/cjs/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/cjs/data-structures/graph/undirected-graph.js +129 -149
- package/dist/cjs/data-structures/graph/undirected-graph.js.map +1 -1
- package/dist/cjs/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/cjs/data-structures/hash/hash-map.js +270 -457
- package/dist/cjs/data-structures/hash/hash-map.js.map +1 -1
- package/dist/cjs/data-structures/heap/heap.d.ts +214 -289
- package/dist/cjs/data-structures/heap/heap.js +340 -349
- package/dist/cjs/data-structures/heap/heap.js.map +1 -1
- package/dist/cjs/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/cjs/data-structures/heap/max-heap.js +11 -66
- package/dist/cjs/data-structures/heap/max-heap.js.map +1 -1
- package/dist/cjs/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/cjs/data-structures/heap/min-heap.js +11 -66
- package/dist/cjs/data-structures/heap/min-heap.js.map +1 -1
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.js +368 -494
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
- package/dist/cjs/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/cjs/data-structures/linked-list/singly-linked-list.js +447 -466
- package/dist/cjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
- package/dist/cjs/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/cjs/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/cjs/data-structures/linked-list/skip-linked-list.js.map +1 -1
- package/dist/cjs/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/cjs/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/cjs/data-structures/priority-queue/max-priority-queue.js.map +1 -1
- package/dist/cjs/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/cjs/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/cjs/data-structures/priority-queue/min-priority-queue.js.map +1 -1
- package/dist/cjs/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/cjs/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/cjs/data-structures/priority-queue/priority-queue.js.map +1 -1
- package/dist/cjs/data-structures/queue/deque.d.ts +227 -254
- package/dist/cjs/data-structures/queue/deque.js +309 -348
- package/dist/cjs/data-structures/queue/deque.js.map +1 -1
- package/dist/cjs/data-structures/queue/queue.d.ts +180 -201
- package/dist/cjs/data-structures/queue/queue.js +265 -248
- package/dist/cjs/data-structures/queue/queue.js.map +1 -1
- package/dist/cjs/data-structures/stack/stack.d.ts +124 -102
- package/dist/cjs/data-structures/stack/stack.js +181 -125
- package/dist/cjs/data-structures/stack/stack.js.map +1 -1
- package/dist/cjs/data-structures/trie/trie.d.ts +164 -165
- package/dist/cjs/data-structures/trie/trie.js +189 -172
- package/dist/cjs/data-structures/trie/trie.js.map +1 -1
- package/dist/cjs/interfaces/binary-tree.d.ts +56 -6
- package/dist/cjs/interfaces/graph.d.ts +16 -0
- package/dist/cjs/types/data-structures/base/base.d.ts +1 -1
- package/dist/cjs/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/cjs/types/utils/utils.d.ts +6 -6
- package/dist/cjs/utils/utils.d.ts +110 -49
- package/dist/cjs/utils/utils.js +148 -73
- package/dist/cjs/utils/utils.js.map +1 -1
- package/dist/esm/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/esm/data-structures/base/iterable-element-base.js +155 -107
- package/dist/esm/data-structures/base/iterable-element-base.js.map +1 -1
- package/dist/esm/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/esm/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/esm/data-structures/base/iterable-entry-base.js.map +1 -1
- package/dist/esm/data-structures/base/linear-base.d.ts +250 -192
- package/dist/esm/data-structures/base/linear-base.js +137 -274
- package/dist/esm/data-structures/base/linear-base.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/esm/data-structures/binary-tree/avl-tree-counter.js +171 -212
- package/dist/esm/data-structures/binary-tree/avl-tree-counter.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.js +133 -94
- package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/esm/data-structures/binary-tree/avl-tree.js +206 -200
- package/dist/esm/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/esm/data-structures/binary-tree/binary-tree.js +613 -885
- package/dist/esm/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/esm/data-structures/binary-tree/bst.js +507 -487
- package/dist/esm/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/esm/data-structures/binary-tree/red-black-tree.js +114 -215
- package/dist/esm/data-structures/binary-tree/red-black-tree.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/esm/data-structures/binary-tree/tree-counter.js +175 -209
- package/dist/esm/data-structures/binary-tree/tree-counter.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/esm/data-structures/binary-tree/tree-multi-map.js +103 -92
- package/dist/esm/data-structures/binary-tree/tree-multi-map.js.map +1 -1
- package/dist/esm/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/esm/data-structures/graph/abstract-graph.js +267 -237
- package/dist/esm/data-structures/graph/abstract-graph.js.map +1 -1
- package/dist/esm/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/esm/data-structures/graph/directed-graph.js +145 -233
- package/dist/esm/data-structures/graph/directed-graph.js.map +1 -1
- package/dist/esm/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/esm/data-structures/graph/map-graph.js +56 -59
- package/dist/esm/data-structures/graph/map-graph.js.map +1 -1
- package/dist/esm/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/esm/data-structures/graph/undirected-graph.js +128 -149
- package/dist/esm/data-structures/graph/undirected-graph.js.map +1 -1
- package/dist/esm/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/esm/data-structures/hash/hash-map.js +270 -457
- package/dist/esm/data-structures/hash/hash-map.js.map +1 -1
- package/dist/esm/data-structures/heap/heap.d.ts +214 -289
- package/dist/esm/data-structures/heap/heap.js +329 -349
- package/dist/esm/data-structures/heap/heap.js.map +1 -1
- package/dist/esm/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/esm/data-structures/heap/max-heap.js +11 -66
- package/dist/esm/data-structures/heap/max-heap.js.map +1 -1
- package/dist/esm/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/esm/data-structures/heap/min-heap.js +11 -66
- package/dist/esm/data-structures/heap/min-heap.js.map +1 -1
- package/dist/esm/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/esm/data-structures/linked-list/doubly-linked-list.js +368 -495
- package/dist/esm/data-structures/linked-list/doubly-linked-list.js.map +1 -1
- package/dist/esm/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/esm/data-structures/linked-list/singly-linked-list.js +448 -467
- package/dist/esm/data-structures/linked-list/singly-linked-list.js.map +1 -1
- package/dist/esm/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/esm/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/esm/data-structures/linked-list/skip-linked-list.js.map +1 -1
- package/dist/esm/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/esm/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/esm/data-structures/priority-queue/max-priority-queue.js.map +1 -1
- package/dist/esm/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/esm/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/esm/data-structures/priority-queue/min-priority-queue.js.map +1 -1
- package/dist/esm/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/esm/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/esm/data-structures/priority-queue/priority-queue.js.map +1 -1
- package/dist/esm/data-structures/queue/deque.d.ts +227 -254
- package/dist/esm/data-structures/queue/deque.js +313 -348
- package/dist/esm/data-structures/queue/deque.js.map +1 -1
- package/dist/esm/data-structures/queue/queue.d.ts +180 -201
- package/dist/esm/data-structures/queue/queue.js +263 -248
- package/dist/esm/data-structures/queue/queue.js.map +1 -1
- package/dist/esm/data-structures/stack/stack.d.ts +124 -102
- package/dist/esm/data-structures/stack/stack.js +181 -125
- package/dist/esm/data-structures/stack/stack.js.map +1 -1
- package/dist/esm/data-structures/trie/trie.d.ts +164 -165
- package/dist/esm/data-structures/trie/trie.js +193 -172
- package/dist/esm/data-structures/trie/trie.js.map +1 -1
- package/dist/esm/interfaces/binary-tree.d.ts +56 -6
- package/dist/esm/interfaces/graph.d.ts +16 -0
- package/dist/esm/types/data-structures/base/base.d.ts +1 -1
- package/dist/esm/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/esm/types/utils/utils.d.ts +6 -6
- package/dist/esm/utils/utils.d.ts +110 -49
- package/dist/esm/utils/utils.js +139 -68
- package/dist/esm/utils/utils.js.map +1 -1
- package/dist/umd/data-structure-typed.js +4737 -6525
- package/dist/umd/data-structure-typed.min.js +8 -6
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +3 -4
- package/src/data-structures/base/iterable-element-base.ts +238 -115
- package/src/data-structures/base/iterable-entry-base.ts +96 -120
- package/src/data-structures/base/linear-base.ts +271 -277
- package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
- package/src/data-structures/binary-tree/avl-tree.ts +239 -206
- package/src/data-structures/binary-tree/binary-tree.ts +677 -901
- package/src/data-structures/binary-tree/bst.ts +568 -570
- package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
- package/src/data-structures/binary-tree/tree-counter.ts +199 -218
- package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
- package/src/data-structures/graph/abstract-graph.ts +339 -264
- package/src/data-structures/graph/directed-graph.ts +146 -236
- package/src/data-structures/graph/map-graph.ts +63 -60
- package/src/data-structures/graph/undirected-graph.ts +129 -152
- package/src/data-structures/hash/hash-map.ts +274 -496
- package/src/data-structures/heap/heap.ts +389 -402
- package/src/data-structures/heap/max-heap.ts +12 -76
- package/src/data-structures/heap/min-heap.ts +13 -76
- package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
- package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
- package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
- package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
- package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
- package/src/data-structures/priority-queue/priority-queue.ts +3 -92
- package/src/data-structures/queue/deque.ts +381 -357
- package/src/data-structures/queue/queue.ts +310 -264
- package/src/data-structures/stack/stack.ts +217 -131
- package/src/data-structures/trie/trie.ts +240 -175
- package/src/interfaces/binary-tree.ts +240 -6
- package/src/interfaces/graph.ts +37 -0
- package/src/types/data-structures/base/base.ts +5 -5
- package/src/types/data-structures/graph/abstract-graph.ts +5 -0
- package/src/types/utils/utils.ts +9 -5
- package/src/utils/utils.ts +152 -86
- package/test/integration/index.html +1 -1
- package/test/performance/benchmark-runner.ts +528 -0
- package/test/performance/reportor.mjs +43 -43
- package/test/performance/runner-config.json +39 -0
- package/test/performance/single-suite-runner.ts +69 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +3 -3
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +5 -5
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +4 -4
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +350 -90
- package/test/unit/data-structures/binary-tree/bst.test.ts +84 -5
- package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +2 -2
- package/test/unit/data-structures/binary-tree/tree-counter.test.ts +25 -24
- package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +3 -3
- package/test/unit/data-structures/graph/abstract-graph.test.ts +0 -4
- package/test/unit/data-structures/graph/directed-graph.test.ts +1 -1
- package/test/unit/data-structures/heap/heap.test.ts +14 -21
- package/test/unit/data-structures/heap/max-heap.test.ts +5 -9
- package/test/unit/data-structures/heap/min-heap.test.ts +1 -4
- package/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +14 -14
- package/test/unit/data-structures/linked-list/singly-linked-list.test.ts +0 -7
- package/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +8 -11
- package/test/unit/data-structures/priority-queue/min-priority-queue.test.ts +1 -4
- package/test/unit/data-structures/priority-queue/priority-queue.test.ts +1 -4
- package/test/unit/data-structures/queue/queue.test.ts +4 -5
- package/test/unit/utils/utils.test.ts +0 -1
- package/test/performance/data-structures/binary-tree/avl-tree.test.mjs +0 -71
- package/test/performance/data-structures/binary-tree/red-black-tree.test.mjs +0 -81
|
@@ -88,8 +88,8 @@ describe('BinaryTreeNode', () => {
|
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
describe('BinaryTree
|
|
92
|
-
it('
|
|
91
|
+
describe('BinaryTree.addMany', () => {
|
|
92
|
+
it('addMany(): adds entries via toEntryFn and values override', () => {
|
|
93
93
|
const binTree = new BinaryTree<number, number, { id: number; name: number }>([], {
|
|
94
94
|
toEntryFn: ({ id, name }) => [id, name]
|
|
95
95
|
});
|
|
@@ -108,7 +108,7 @@ describe('BinaryTree addMany', () => {
|
|
|
108
108
|
expect(binTree.get(binTree.getNode(1))).toBe(1);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('
|
|
111
|
+
it('addMany(): handles undefined and null keys', () => {
|
|
112
112
|
const binaryTree = new BinaryTree<number, string>();
|
|
113
113
|
const addManyWithUndefined = binaryTree.addMany([1, undefined, 3]);
|
|
114
114
|
expect(addManyWithUndefined).toEqual([true, false, true]);
|
|
@@ -143,16 +143,16 @@ describe('BinaryTree', () => {
|
|
|
143
143
|
binTree.clear();
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
-
it('
|
|
146
|
+
it('add(): inserts a node and updates size', () => {
|
|
147
147
|
const node = binTree.add(1);
|
|
148
148
|
expect(node).not.toBeNull();
|
|
149
149
|
expect(binTree.size).toBe(1);
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
it('
|
|
152
|
+
it('delete(): leaf/one-child/two-children/missing; updates size and minHeight', () => {
|
|
153
153
|
expect(binTree.getHeight(binTree.root, 'ITERATIVE')).toBe(-1);
|
|
154
154
|
expect(binTree.getMinHeight()).toBe(-1);
|
|
155
|
-
const node1 = binTree.
|
|
155
|
+
const node1 = binTree._createNode(1);
|
|
156
156
|
binTree.add(node1);
|
|
157
157
|
expect(binTree.size).toBe(1);
|
|
158
158
|
|
|
@@ -182,7 +182,7 @@ describe('BinaryTree', () => {
|
|
|
182
182
|
}
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
-
it('
|
|
185
|
+
it('add()/has()/getNode(): find nodes by key and predicate', () => {
|
|
186
186
|
binTree.add([1, 1]);
|
|
187
187
|
binTree.add(undefined);
|
|
188
188
|
binTree.add([2, 2]);
|
|
@@ -198,7 +198,7 @@ describe('BinaryTree', () => {
|
|
|
198
198
|
expect(binTree.has(node => node.key?.toString() === '3')).toBe(true);
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
-
it('
|
|
201
|
+
it('clone(): structural copy; subtree dfs with includeNull permutations', () => {
|
|
202
202
|
expect(binTree.isEmpty()).toBe(true);
|
|
203
203
|
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
|
204
204
|
expect(binTree.root?.key).toBe(4);
|
|
@@ -252,7 +252,7 @@ describe('BinaryTree', () => {
|
|
|
252
252
|
// expect(cloned.isEmpty()).toBe(true);
|
|
253
253
|
});
|
|
254
254
|
|
|
255
|
-
it('
|
|
255
|
+
it('isPerfectlyBalanced(): toggles with pointer tampering and skewed levels', () => {
|
|
256
256
|
binTree.add(3);
|
|
257
257
|
binTree.add(12);
|
|
258
258
|
binTree.addMany(getRandomIntArray(100, 1, 100));
|
|
@@ -261,7 +261,7 @@ describe('BinaryTree', () => {
|
|
|
261
261
|
expect(binTree.isPerfectlyBalanced()).toBe(true);
|
|
262
262
|
const node3 = binTree.getNode(3);
|
|
263
263
|
|
|
264
|
-
if (node3) node3.right = binTree.
|
|
264
|
+
if (node3) node3.right = binTree._createNode(1);
|
|
265
265
|
expect(binTree.isPerfectlyBalanced()).toBe(false);
|
|
266
266
|
|
|
267
267
|
binTree.clear();
|
|
@@ -269,7 +269,7 @@ describe('BinaryTree', () => {
|
|
|
269
269
|
expect(binTree.isPerfectlyBalanced()).toBe(false);
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
it('
|
|
272
|
+
it('getDepth(): returns correct depth with/without root parameter', () => {
|
|
273
273
|
binTree.add(1);
|
|
274
274
|
expect(binTree.getDepth(1)).toBe(0);
|
|
275
275
|
binTree.add(2);
|
|
@@ -282,7 +282,7 @@ describe('BinaryTree', () => {
|
|
|
282
282
|
expect(binTree.getDepth(4, 2)).toBe(1);
|
|
283
283
|
});
|
|
284
284
|
|
|
285
|
-
it('
|
|
285
|
+
it('dfs(IN): returns in-order; height respects iterationType', () => {
|
|
286
286
|
binTree.add(null);
|
|
287
287
|
binTree.delete(1);
|
|
288
288
|
expect(binTree.getHeight()).toBe(-1);
|
|
@@ -304,7 +304,7 @@ describe('BinaryTree', () => {
|
|
|
304
304
|
expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]);
|
|
305
305
|
});
|
|
306
306
|
|
|
307
|
-
it('
|
|
307
|
+
it('isBST(): returns true for subtree (iterative & recursive)', () => {
|
|
308
308
|
binTree.addMany([
|
|
309
309
|
new BinaryTreeNode(4, 4),
|
|
310
310
|
new BinaryTreeNode(2, 2),
|
|
@@ -320,7 +320,7 @@ describe('BinaryTree', () => {
|
|
|
320
320
|
expect(binTree.isBST(binTree.getNode(4), 'ITERATIVE')).toBe(true);
|
|
321
321
|
});
|
|
322
322
|
|
|
323
|
-
it('
|
|
323
|
+
it('isBST(): returns true for subtree (iterative & recursive)', () => {
|
|
324
324
|
expect(binTree.toVisual()).toBe('');
|
|
325
325
|
binTree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
|
|
326
326
|
expect(binTree.toVisual()).toBe(
|
|
@@ -358,9 +358,9 @@ describe('BinaryTree', () => {
|
|
|
358
358
|
expect(binTree.getNodes(binTree.getNode(2), false, binTree.root)).toEqual([binTree.getNode(2)]);
|
|
359
359
|
});
|
|
360
360
|
|
|
361
|
-
describe('
|
|
361
|
+
describe('isValidKey', () => {
|
|
362
362
|
describe('primitive types', () => {
|
|
363
|
-
it('numbers
|
|
363
|
+
it('isValidKey(): numbers are valid keys', () => {
|
|
364
364
|
expect(binTree.isValidKey(42)).toBe(true);
|
|
365
365
|
expect(binTree.isValidKey(0)).toBe(true);
|
|
366
366
|
expect(binTree.isValidKey(-1)).toBe(true);
|
|
@@ -368,40 +368,40 @@ describe('BinaryTree', () => {
|
|
|
368
368
|
expect(binTree.isValidKey(-Infinity)).toBe(true);
|
|
369
369
|
});
|
|
370
370
|
|
|
371
|
-
// it('NaN
|
|
371
|
+
// it('isValidKey(): NaN is not a valid key', () => {
|
|
372
372
|
// expect(binTree.isValidKey(NaN)).toBe(false);
|
|
373
373
|
// });
|
|
374
374
|
|
|
375
|
-
it('strings
|
|
375
|
+
it('isValidKey(): strings are valid keys', () => {
|
|
376
376
|
expect(binTree.isValidKey('hello')).toBe(true);
|
|
377
377
|
expect(binTree.isValidKey('')).toBe(true);
|
|
378
378
|
expect(binTree.isValidKey('123')).toBe(true);
|
|
379
379
|
});
|
|
380
380
|
|
|
381
|
-
it('BigInt
|
|
381
|
+
it('isValidKey(): BigInt is a valid key', () => {
|
|
382
382
|
expect(binTree.isValidKey(BigInt(42))).toBe(true);
|
|
383
383
|
expect(binTree.isValidKey(BigInt(0))).toBe(true);
|
|
384
384
|
expect(binTree.isValidKey(BigInt(-1))).toBe(true);
|
|
385
385
|
});
|
|
386
386
|
|
|
387
|
-
it('
|
|
387
|
+
it('isValidKey(): booleans are valid keys', () => {
|
|
388
388
|
expect(binTree.isValidKey(true)).toBe(true);
|
|
389
389
|
expect(binTree.isValidKey(false)).toBe(true);
|
|
390
390
|
});
|
|
391
391
|
|
|
392
|
-
it('null
|
|
392
|
+
it('isValidKey(): null is valid, undefined is not', () => {
|
|
393
393
|
expect(binTree.isValidKey(null)).toBe(true);
|
|
394
394
|
expect(binTree.isValidKey(undefined)).toBe(false);
|
|
395
395
|
});
|
|
396
396
|
|
|
397
|
-
it('symbols
|
|
397
|
+
it('isValidKey(): symbols are not valid keys', () => {
|
|
398
398
|
expect(binTree.isValidKey(Symbol('test'))).toBe(false);
|
|
399
399
|
expect(binTree.isValidKey(Symbol.for('test'))).toBe(false);
|
|
400
400
|
});
|
|
401
401
|
});
|
|
402
402
|
|
|
403
403
|
describe('Date objects', () => {
|
|
404
|
-
it('valid Date objects
|
|
404
|
+
it('isValidKey(): valid Date objects are valid keys', () => {
|
|
405
405
|
expect(binTree.isValidKey(new Date())).toBe(true);
|
|
406
406
|
expect(binTree.isValidKey(new Date('2024-01-01'))).toBe(true);
|
|
407
407
|
});
|
|
@@ -412,7 +412,7 @@ describe('BinaryTree', () => {
|
|
|
412
412
|
});
|
|
413
413
|
|
|
414
414
|
describe('arrays', () => {
|
|
415
|
-
it('arrays
|
|
415
|
+
it('isValidKey(): arrays are valid (stringified) keys', () => {
|
|
416
416
|
expect(binTree.isValidKey([])).toBe(true);
|
|
417
417
|
expect(binTree.isValidKey([1, 2, 3])).toBe(true);
|
|
418
418
|
expect(binTree.isValidKey(['a', 'b', 'c'])).toBe(true);
|
|
@@ -420,26 +420,26 @@ describe('BinaryTree', () => {
|
|
|
420
420
|
});
|
|
421
421
|
|
|
422
422
|
describe('plain objects', () => {
|
|
423
|
-
it('plain objects
|
|
423
|
+
it('isValidKey(): plain objects are not valid keys', () => {
|
|
424
424
|
expect(binTree.isValidKey({})).toBe(false);
|
|
425
425
|
expect(binTree.isValidKey({ a: 1 })).toBe(false);
|
|
426
426
|
});
|
|
427
427
|
});
|
|
428
428
|
|
|
429
429
|
describe('custom objects', () => {
|
|
430
|
-
it('objects with numeric valueOf
|
|
430
|
+
it('isValidKey(): objects with numeric valueOf are valid keys', () => {
|
|
431
431
|
expect(binTree.isValidKey({ valueOf: () => 42 })).toBe(true);
|
|
432
432
|
});
|
|
433
433
|
|
|
434
|
-
it('objects with string valueOf
|
|
434
|
+
it('isValidKey(): objects with string valueOf are valid keys', () => {
|
|
435
435
|
expect(binTree.isValidKey({ valueOf: () => 'test' })).toBe(true);
|
|
436
436
|
});
|
|
437
437
|
|
|
438
|
-
it('objects with boolean valueOf
|
|
438
|
+
it('isValidKey(): objects with boolean valueOf are treated as valid', () => {
|
|
439
439
|
expect(binTree.isValidKey({ valueOf: () => true })).toBe(true);
|
|
440
440
|
});
|
|
441
441
|
|
|
442
|
-
it('
|
|
442
|
+
it('isValidKey(): nested valueOf/toString results in valid key', () => {
|
|
443
443
|
expect(
|
|
444
444
|
binTree.isValidKey({
|
|
445
445
|
valueOf: () => ({ toString: () => '42' })
|
|
@@ -449,7 +449,7 @@ describe('BinaryTree', () => {
|
|
|
449
449
|
});
|
|
450
450
|
|
|
451
451
|
describe('deeply nested objects', () => {
|
|
452
|
-
it('
|
|
452
|
+
it('isValidKey(): deeply nested valueOf is valid', () => {
|
|
453
453
|
const deeplyNested = {
|
|
454
454
|
valueOf: () => ({
|
|
455
455
|
valueOf: () => 42
|
|
@@ -458,7 +458,7 @@ describe('BinaryTree', () => {
|
|
|
458
458
|
expect(binTree.isValidKey(deeplyNested)).toBe(true);
|
|
459
459
|
});
|
|
460
460
|
|
|
461
|
-
it('
|
|
461
|
+
it('isValidKey(): very deep conversion to string is valid', () => {
|
|
462
462
|
const veryDeeplyNested = {
|
|
463
463
|
valueOf: () => ({
|
|
464
464
|
valueOf: () => ({
|
|
@@ -469,7 +469,7 @@ describe('BinaryTree', () => {
|
|
|
469
469
|
expect(binTree.isValidKey(veryDeeplyNested)).toBe(true);
|
|
470
470
|
});
|
|
471
471
|
|
|
472
|
-
it('
|
|
472
|
+
it('isValidKey(): circular reference is invalid', () => {
|
|
473
473
|
const circular: any = {
|
|
474
474
|
valueOf: () => circular
|
|
475
475
|
};
|
|
@@ -478,7 +478,7 @@ describe('BinaryTree', () => {
|
|
|
478
478
|
});
|
|
479
479
|
|
|
480
480
|
describe('edge cases', () => {
|
|
481
|
-
it('
|
|
481
|
+
it('isValidKey(): non-primitive ultimate value is invalid', () => {
|
|
482
482
|
const complexObject = {
|
|
483
483
|
valueOf: () => ({
|
|
484
484
|
toString: () => ({
|
|
@@ -489,7 +489,7 @@ describe('BinaryTree', () => {
|
|
|
489
489
|
expect(binTree.isValidKey(complexObject)).toBe(false);
|
|
490
490
|
});
|
|
491
491
|
|
|
492
|
-
it('
|
|
492
|
+
it('isValidKey(): ultimately primitive conversion is valid', () => {
|
|
493
493
|
const complexObject = {
|
|
494
494
|
valueOf: () => ({
|
|
495
495
|
valueOf: () => ({
|
|
@@ -508,7 +508,7 @@ describe('BinaryTree', () => {
|
|
|
508
508
|
});
|
|
509
509
|
|
|
510
510
|
describe('type checking', () => {
|
|
511
|
-
it('
|
|
511
|
+
it('isValidKey(): works as a type guard in array methods', () => {
|
|
512
512
|
const values: unknown[] = [42, 'test', true, null, undefined, new Date()];
|
|
513
513
|
const comparableValues = values.filter(item => binTree.isValidKey(item));
|
|
514
514
|
expect(comparableValues.length).toBe(5);
|
|
@@ -516,7 +516,7 @@ describe('BinaryTree', () => {
|
|
|
516
516
|
});
|
|
517
517
|
});
|
|
518
518
|
|
|
519
|
-
it('
|
|
519
|
+
it('isLeaf(): detects leaves; null is treated as leaf', () => {
|
|
520
520
|
expect(binTree.getLeftMost()).toBe(undefined);
|
|
521
521
|
expect(binTree.getRightMost()).toBe(undefined);
|
|
522
522
|
binTree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
|
|
@@ -528,7 +528,7 @@ describe('BinaryTree', () => {
|
|
|
528
528
|
expect(binTree.isLeaf(null)).toBe(true);
|
|
529
529
|
});
|
|
530
530
|
|
|
531
|
-
it('
|
|
531
|
+
it('dfs/bfs on mixed-null level-order tree: expected orders (includeNull on/off)', () => {
|
|
532
532
|
expect(binTree.dfs()).toEqual([]);
|
|
533
533
|
expect([...binTree.values()]).toEqual([]);
|
|
534
534
|
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
|
@@ -617,7 +617,7 @@ describe('BinaryTree', () => {
|
|
|
617
617
|
);
|
|
618
618
|
});
|
|
619
619
|
|
|
620
|
-
it('
|
|
620
|
+
it('dfs on subtree (startNode): expected orders (includeNull on/off)', () => {
|
|
621
621
|
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
|
622
622
|
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
|
|
623
623
|
expect(
|
|
@@ -668,7 +668,7 @@ describe('BinaryTree', () => {
|
|
|
668
668
|
).toEqual([7, 3, null, 6]);
|
|
669
669
|
});
|
|
670
670
|
|
|
671
|
-
it('
|
|
671
|
+
it('clear(): empties tree and resets root', () => {
|
|
672
672
|
binTree.add(1);
|
|
673
673
|
binTree.add(2);
|
|
674
674
|
|
|
@@ -680,7 +680,7 @@ describe('BinaryTree', () => {
|
|
|
680
680
|
expect(binTree.root).toBeUndefined();
|
|
681
681
|
});
|
|
682
682
|
|
|
683
|
-
it('
|
|
683
|
+
it('duplicate keys: replace existing value; bfs includeNull snapshot', function () {
|
|
684
684
|
binTree.clear();
|
|
685
685
|
expect(binTree.bfs()).toEqual([]);
|
|
686
686
|
binTree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
|
|
@@ -739,7 +739,7 @@ describe('BinaryTree', () => {
|
|
|
739
739
|
// expect(bTree.keyValueNodeEntryRawToNodeAndValue({ obj: { id: 1 } })).toEqual([undefined, undefined]);
|
|
740
740
|
// });
|
|
741
741
|
|
|
742
|
-
it('
|
|
742
|
+
it('add(): duplicate key updates value (Map vs non-Map behavior)', () => {
|
|
743
743
|
const binTree = new BinaryTree<number, string>([4, 5, [1, '1'], 2, 3], { isMapMode: false });
|
|
744
744
|
expect(binTree.get(1)).toBe('1');
|
|
745
745
|
expect(binTree.getNode(1)?.value).toBe('1');
|
|
@@ -759,8 +759,8 @@ describe('BinaryTree', () => {
|
|
|
759
759
|
});
|
|
760
760
|
});
|
|
761
761
|
|
|
762
|
-
describe('BinaryTree
|
|
763
|
-
it('
|
|
762
|
+
describe('BinaryTree.ensureNode', () => {
|
|
763
|
+
it('ensureNode(): with toEntryFn returns existing node; handles null/undefined/Symbol', () => {
|
|
764
764
|
const binTree = new BinaryTree<
|
|
765
765
|
number,
|
|
766
766
|
string,
|
|
@@ -779,7 +779,7 @@ describe('BinaryTree ensureNode', () => {
|
|
|
779
779
|
});
|
|
780
780
|
});
|
|
781
781
|
|
|
782
|
-
describe('BinaryTree Morris
|
|
782
|
+
describe('BinaryTree - Morris traversal', () => {
|
|
783
783
|
// Create a binary binTree
|
|
784
784
|
const binTree = new BinaryTree<number>();
|
|
785
785
|
binTree.add(1);
|
|
@@ -787,7 +787,7 @@ describe('BinaryTree Morris Traversal', () => {
|
|
|
787
787
|
binTree.add(3);
|
|
788
788
|
binTree.add(4);
|
|
789
789
|
binTree.add(5);
|
|
790
|
-
it('
|
|
790
|
+
it('morris(IN): equals dfs(IN) (iterative/recursive)', () => {
|
|
791
791
|
// Perform in-order Morris traversal
|
|
792
792
|
const result = binTree.morris(node => node.key, 'IN');
|
|
793
793
|
|
|
@@ -799,7 +799,7 @@ describe('BinaryTree Morris Traversal', () => {
|
|
|
799
799
|
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
|
800
800
|
});
|
|
801
801
|
|
|
802
|
-
it('
|
|
802
|
+
it('morris(PRE): equals dfs(PRE)', () => {
|
|
803
803
|
// Perform pre-order Morris traversal
|
|
804
804
|
const result = binTree.morris(node => node.key, 'PRE');
|
|
805
805
|
|
|
@@ -810,7 +810,7 @@ describe('BinaryTree Morris Traversal', () => {
|
|
|
810
810
|
expect(binTree.dfs(node => node.key, 'PRE')).toEqual(expected);
|
|
811
811
|
});
|
|
812
812
|
|
|
813
|
-
it('
|
|
813
|
+
it('morris(POST): equals dfs(POST)', () => {
|
|
814
814
|
// Perform post-order Morris traversal
|
|
815
815
|
const result = binTree.morris(node => node.key, 'POST');
|
|
816
816
|
|
|
@@ -821,7 +821,7 @@ describe('BinaryTree Morris Traversal', () => {
|
|
|
821
821
|
expect(binTree.dfs(node => node.key, 'POST')).toEqual(expected);
|
|
822
822
|
});
|
|
823
823
|
|
|
824
|
-
it('
|
|
824
|
+
it('morris(): structure intact afterwards', () => {
|
|
825
825
|
const node1 = binTree.getNode(1);
|
|
826
826
|
const node2 = binTree.getNode(2);
|
|
827
827
|
const node3 = binTree.getNode(3);
|
|
@@ -830,8 +830,8 @@ describe('BinaryTree Morris Traversal', () => {
|
|
|
830
830
|
});
|
|
831
831
|
});
|
|
832
832
|
|
|
833
|
-
describe('BinaryTree
|
|
834
|
-
it('
|
|
833
|
+
describe('BinaryTree.toEntryFn', () => {
|
|
834
|
+
it('toEntryFn: non-function throws toEntryFn must be a function type', () => {
|
|
835
835
|
expect(() => {
|
|
836
836
|
new BinaryTree<number, number, { obj: { id: number } }>([], {
|
|
837
837
|
toEntryFn: `ele => [ele.obj.id, ele.obj.id]` as unknown as (rawElement: {
|
|
@@ -841,7 +841,7 @@ describe('BinaryTree toEntryFn', () => {
|
|
|
841
841
|
}).toThrow('toEntryFn must be a function type');
|
|
842
842
|
});
|
|
843
843
|
|
|
844
|
-
it('
|
|
844
|
+
it('toEntryFn + addMany(): IN order equals dfs/Morris', () => {
|
|
845
845
|
const binTree = new BinaryTree<number, number, { obj: { id: number } }>([], {
|
|
846
846
|
toEntryFn: ele => [ele.obj.id, ele.obj.id]
|
|
847
847
|
});
|
|
@@ -860,7 +860,7 @@ describe('BinaryTree toEntryFn', () => {
|
|
|
860
860
|
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
|
861
861
|
});
|
|
862
862
|
|
|
863
|
-
it('
|
|
863
|
+
it('constructor toEntryFn (initial data): IN order equals dfs/Morris', () => {
|
|
864
864
|
const binTree = new BinaryTree<number, number, { obj: { id: number } }>(
|
|
865
865
|
[{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }],
|
|
866
866
|
{
|
|
@@ -875,7 +875,7 @@ describe('BinaryTree toEntryFn', () => {
|
|
|
875
875
|
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
|
|
876
876
|
});
|
|
877
877
|
|
|
878
|
-
it('
|
|
878
|
+
it('without toEntryFn (valueOf-based): dfs/Morris behaviors', () => {
|
|
879
879
|
const data = [
|
|
880
880
|
{ obj: { id: 4 }, valueOf: () => 4 },
|
|
881
881
|
{ obj: { id: 2 }, valueOf: () => 2 },
|
|
@@ -891,8 +891,8 @@ describe('BinaryTree toEntryFn', () => {
|
|
|
891
891
|
});
|
|
892
892
|
});
|
|
893
893
|
|
|
894
|
-
describe('BinaryTree
|
|
895
|
-
it('
|
|
894
|
+
describe('BinaryTree - traversal suites', () => {
|
|
895
|
+
it('bfs/dfs/listLevels: permutations return expected sequences', () => {
|
|
896
896
|
const binTree = new BinaryTree<number>();
|
|
897
897
|
|
|
898
898
|
const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55];
|
|
@@ -997,13 +997,13 @@ describe('BinaryTree', () => {
|
|
|
997
997
|
binTree.clear();
|
|
998
998
|
});
|
|
999
999
|
|
|
1000
|
-
it('
|
|
1000
|
+
it('constructor: creates an empty BinaryTree', () => {
|
|
1001
1001
|
expect(binTree.size).toBe(0);
|
|
1002
1002
|
expect(binTree.isEmpty()).toBe(true);
|
|
1003
1003
|
expect(binTree.root).toBe(undefined);
|
|
1004
1004
|
});
|
|
1005
1005
|
|
|
1006
|
-
it('
|
|
1006
|
+
it('add(): inserts nodes and sets root', () => {
|
|
1007
1007
|
binTree.add([5, 'A']);
|
|
1008
1008
|
binTree.add([3, 'B']);
|
|
1009
1009
|
binTree.add([7, 'C']);
|
|
@@ -1025,7 +1025,7 @@ describe('BinaryTree', () => {
|
|
|
1025
1025
|
expect(binTree.root).toBe(undefined);
|
|
1026
1026
|
});
|
|
1027
1027
|
|
|
1028
|
-
it('
|
|
1028
|
+
it('getNode()/get(): resolve nodes and values by key', () => {
|
|
1029
1029
|
binTree.add([5, 'A']);
|
|
1030
1030
|
binTree.add([3, 'B']);
|
|
1031
1031
|
binTree.add([7, 'C']);
|
|
@@ -1039,7 +1039,7 @@ describe('BinaryTree', () => {
|
|
|
1039
1039
|
expect(binTree.get(nodeB)).toBe('B');
|
|
1040
1040
|
});
|
|
1041
1041
|
|
|
1042
|
-
it('
|
|
1042
|
+
it('getNode(): returns undefined for missing key', () => {
|
|
1043
1043
|
binTree.add([5, 'A']);
|
|
1044
1044
|
|
|
1045
1045
|
const node = binTree.getNode(3);
|
|
@@ -1056,7 +1056,7 @@ describe('BinaryTree', () => {
|
|
|
1056
1056
|
expect(binTree.getDepth(3)).toBe(1);
|
|
1057
1057
|
});
|
|
1058
1058
|
|
|
1059
|
-
it('
|
|
1059
|
+
it('getHeight()/getMinHeight(): expected heights', () => {
|
|
1060
1060
|
expect(binTree.getMinHeight()).toBe(-1);
|
|
1061
1061
|
binTree.add([5, 'A']);
|
|
1062
1062
|
binTree.add(3, 'B');
|
|
@@ -1067,7 +1067,7 @@ describe('BinaryTree', () => {
|
|
|
1067
1067
|
expect(binTree.getMinHeight(undefined, 'RECURSIVE')).toBe(1);
|
|
1068
1068
|
});
|
|
1069
1069
|
|
|
1070
|
-
it('
|
|
1070
|
+
it('isBST(): returns true for valid tree', () => {
|
|
1071
1071
|
binTree.add([5, 'A']);
|
|
1072
1072
|
binTree.add([3, 'B']);
|
|
1073
1073
|
binTree.add([7, 'C']);
|
|
@@ -1075,7 +1075,7 @@ describe('BinaryTree', () => {
|
|
|
1075
1075
|
expect(binTree.isBST()).toBe(true);
|
|
1076
1076
|
});
|
|
1077
1077
|
|
|
1078
|
-
it('
|
|
1078
|
+
it('dfs(default IN): returns expected order', () => {
|
|
1079
1079
|
binTree.add([5, 'A']);
|
|
1080
1080
|
binTree.add([3, 'B']);
|
|
1081
1081
|
binTree.add([7, 'C']);
|
|
@@ -1085,7 +1085,7 @@ describe('BinaryTree', () => {
|
|
|
1085
1085
|
// Add assertions for the result of depth-first traversal
|
|
1086
1086
|
});
|
|
1087
1087
|
|
|
1088
|
-
it('
|
|
1088
|
+
it('bfs(): returns expected level-order', () => {
|
|
1089
1089
|
binTree.add([5, 'A']);
|
|
1090
1090
|
binTree.add([3, 'B']);
|
|
1091
1091
|
binTree.add([7, 'C']);
|
|
@@ -1095,7 +1095,7 @@ describe('BinaryTree', () => {
|
|
|
1095
1095
|
// Add assertions for the result of breadth-first traversal
|
|
1096
1096
|
});
|
|
1097
1097
|
|
|
1098
|
-
it('
|
|
1098
|
+
it('listLevels(): returns keys by level', () => {
|
|
1099
1099
|
binTree.add([5, 'A']);
|
|
1100
1100
|
binTree.add([3, 'B']);
|
|
1101
1101
|
binTree.add([7, 'C']);
|
|
@@ -1105,7 +1105,7 @@ describe('BinaryTree', () => {
|
|
|
1105
1105
|
// Add assertions for the levels of the binTree
|
|
1106
1106
|
});
|
|
1107
1107
|
|
|
1108
|
-
it('
|
|
1108
|
+
it('delete(): removes nodes and updates size', () => {
|
|
1109
1109
|
binTree.add([5, 'A']);
|
|
1110
1110
|
binTree.add([3, 'B']);
|
|
1111
1111
|
binTree.add([7, 'C']);
|
|
@@ -1116,7 +1116,7 @@ describe('BinaryTree', () => {
|
|
|
1116
1116
|
expect(binTree.getNode(3)).toBe(undefined);
|
|
1117
1117
|
});
|
|
1118
1118
|
|
|
1119
|
-
it('
|
|
1119
|
+
it('getPathToRoot(): path from key to root; [] for missing', () => {
|
|
1120
1120
|
binTree.add([5, 'A']);
|
|
1121
1121
|
binTree.add([3, 'B']);
|
|
1122
1122
|
binTree.add([7, 'C']);
|
|
@@ -1125,7 +1125,7 @@ describe('BinaryTree', () => {
|
|
|
1125
1125
|
expect(binTree.getPathToRoot(1)).toEqual([]);
|
|
1126
1126
|
});
|
|
1127
1127
|
|
|
1128
|
-
it('
|
|
1128
|
+
it('isPerfectlyBalanced(): true for balanced tree', () => {
|
|
1129
1129
|
binTree.add([5, 'A']);
|
|
1130
1130
|
binTree.add([3, 'B']);
|
|
1131
1131
|
binTree.add([7, 'C']);
|
|
@@ -1133,7 +1133,7 @@ describe('BinaryTree', () => {
|
|
|
1133
1133
|
expect(binTree.isPerfectlyBalanced()).toBe(true);
|
|
1134
1134
|
});
|
|
1135
1135
|
|
|
1136
|
-
it('
|
|
1136
|
+
it('getNodes(predicate): returns matches (iterative & recursive)', () => {
|
|
1137
1137
|
binTree.add([5, 'E']);
|
|
1138
1138
|
binTree.add([4, 'D']);
|
|
1139
1139
|
binTree.add([3, 'C']);
|
|
@@ -1163,7 +1163,7 @@ describe('BinaryTree', () => {
|
|
|
1163
1163
|
expect(nodesItr).toEqual(nodesRec);
|
|
1164
1164
|
});
|
|
1165
1165
|
|
|
1166
|
-
it('
|
|
1166
|
+
it('morris(IN): equals dfs(IN); clear() => []', () => {
|
|
1167
1167
|
binTree.add([5, 'A']);
|
|
1168
1168
|
binTree.add([3, 'B']);
|
|
1169
1169
|
binTree.add([7, 'C']);
|
|
@@ -1188,7 +1188,7 @@ describe('BinaryTree', () => {
|
|
|
1188
1188
|
expect(binTree.morris()).toEqual([]);
|
|
1189
1189
|
});
|
|
1190
1190
|
|
|
1191
|
-
it('
|
|
1191
|
+
it('delete(): removes all nodes; height == -1', () => {
|
|
1192
1192
|
binTree.add([5, 'A']);
|
|
1193
1193
|
binTree.add([3, 'B']);
|
|
1194
1194
|
binTree.add([7, 'C']);
|
|
@@ -1201,7 +1201,7 @@ describe('BinaryTree', () => {
|
|
|
1201
1201
|
});
|
|
1202
1202
|
});
|
|
1203
1203
|
|
|
1204
|
-
describe('BinaryTree
|
|
1204
|
+
describe('BinaryTree (non-Map mode)', () => {
|
|
1205
1205
|
let binTree: BinaryTree<number, string>;
|
|
1206
1206
|
|
|
1207
1207
|
beforeEach(() => {
|
|
@@ -1215,7 +1215,7 @@ describe('BinaryTree not map mode', () => {
|
|
|
1215
1215
|
binTree.clear();
|
|
1216
1216
|
});
|
|
1217
1217
|
|
|
1218
|
-
it('
|
|
1218
|
+
it('add()/has()/getNode(): find nodes by key and predicate', () => {
|
|
1219
1219
|
binTree.add([1, '1']);
|
|
1220
1220
|
binTree.add(undefined);
|
|
1221
1221
|
binTree.add([2, '2']);
|
|
@@ -1231,7 +1231,7 @@ describe('BinaryTree not map mode', () => {
|
|
|
1231
1231
|
expect(binTree.has(node => node.value?.toString() === '3')).toBe(true);
|
|
1232
1232
|
});
|
|
1233
1233
|
|
|
1234
|
-
it('
|
|
1234
|
+
it('isBST(): returns true for subtree (iterative & recursive)', () => {
|
|
1235
1235
|
binTree.addMany([
|
|
1236
1236
|
new BinaryTreeNode(4),
|
|
1237
1237
|
new BinaryTreeNode(2),
|
|
@@ -1247,7 +1247,7 @@ describe('BinaryTree not map mode', () => {
|
|
|
1247
1247
|
expect(binTree.isBST(binTree.getNode(4), 'ITERATIVE')).toBe(true);
|
|
1248
1248
|
});
|
|
1249
1249
|
|
|
1250
|
-
it('
|
|
1250
|
+
it('getNode()/get(): resolve nodes and values by key', () => {
|
|
1251
1251
|
binTree.add([5, 'A']);
|
|
1252
1252
|
binTree.add([3, 'B']);
|
|
1253
1253
|
binTree.add([7, 'C']);
|
|
@@ -1261,7 +1261,7 @@ describe('BinaryTree not map mode', () => {
|
|
|
1261
1261
|
expect(binTree.get(nodeB)).toBe('B');
|
|
1262
1262
|
});
|
|
1263
1263
|
|
|
1264
|
-
it('
|
|
1264
|
+
it('getNodes(predicate): returns matches (iterative & recursive)', () => {
|
|
1265
1265
|
binTree.add([5, 'E']);
|
|
1266
1266
|
binTree.add([4, 'D']);
|
|
1267
1267
|
binTree.add([3, 'C']);
|
|
@@ -1292,7 +1292,7 @@ describe('BinaryTree not map mode', () => {
|
|
|
1292
1292
|
});
|
|
1293
1293
|
});
|
|
1294
1294
|
|
|
1295
|
-
describe('BinaryTree
|
|
1295
|
+
describe('BinaryTree (map mode) - higher-order & iteration', () => {
|
|
1296
1296
|
let binaryTree: BinaryTree<number, string>;
|
|
1297
1297
|
beforeEach(() => {
|
|
1298
1298
|
binaryTree = new BinaryTree();
|
|
@@ -1301,12 +1301,12 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1301
1301
|
binaryTree.add([3, 'c']);
|
|
1302
1302
|
});
|
|
1303
1303
|
|
|
1304
|
-
it('
|
|
1304
|
+
it('getNode(): returns BinaryTreeNode instance', () => {
|
|
1305
1305
|
const node3 = binaryTree.getNode(3);
|
|
1306
1306
|
expect(node3).toBeInstanceOf(BinaryTreeNode);
|
|
1307
1307
|
});
|
|
1308
1308
|
|
|
1309
|
-
it('forEach
|
|
1309
|
+
it('forEach(): iterates all entries', () => {
|
|
1310
1310
|
const mockCallback = jest.fn();
|
|
1311
1311
|
binaryTree.forEach((key, value) => {
|
|
1312
1312
|
mockCallback(key, value);
|
|
@@ -1318,7 +1318,7 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1318
1318
|
expect(mockCallback.mock.calls[2]).toEqual([3, 'c']);
|
|
1319
1319
|
});
|
|
1320
1320
|
|
|
1321
|
-
it('filter
|
|
1321
|
+
it('filter(): returns new tree with filtered entries', () => {
|
|
1322
1322
|
const filteredTree = binaryTree.filter(key => key > 1);
|
|
1323
1323
|
expect(filteredTree.size).toBe(2);
|
|
1324
1324
|
expect([...filteredTree]).toEqual([
|
|
@@ -1327,7 +1327,7 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1327
1327
|
]);
|
|
1328
1328
|
});
|
|
1329
1329
|
|
|
1330
|
-
it('map
|
|
1330
|
+
it('map(): returns new tree with transformed keys/values', () => {
|
|
1331
1331
|
const mappedTree = binaryTree.map((key, value) => [(key * 2).toString(), value]);
|
|
1332
1332
|
expect(mappedTree.size).toBe(3);
|
|
1333
1333
|
expect([...mappedTree]).toEqual([
|
|
@@ -1337,12 +1337,12 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1337
1337
|
]);
|
|
1338
1338
|
});
|
|
1339
1339
|
|
|
1340
|
-
it('reduce
|
|
1340
|
+
it('reduce(): aggregates over entries', () => {
|
|
1341
1341
|
const sum = binaryTree.reduce((acc, currentValue, currentKey) => acc + currentKey, 0);
|
|
1342
1342
|
expect(sum).toBe(6);
|
|
1343
1343
|
});
|
|
1344
1344
|
|
|
1345
|
-
it('[Symbol.iterator]
|
|
1345
|
+
it('[Symbol.iterator]: yields entries', () => {
|
|
1346
1346
|
const entries = [];
|
|
1347
1347
|
for (const entry of binaryTree) {
|
|
1348
1348
|
entries.push(entry);
|
|
@@ -1356,31 +1356,31 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1356
1356
|
]);
|
|
1357
1357
|
});
|
|
1358
1358
|
|
|
1359
|
-
it('
|
|
1359
|
+
it('clone(): preserves structure and allows get() by node', () => {
|
|
1360
1360
|
const cloned = binaryTree.clone();
|
|
1361
1361
|
expect(cloned.root?.left?.key).toBe(2);
|
|
1362
1362
|
expect(cloned.root?.right?.value).toBe(undefined);
|
|
1363
1363
|
expect(cloned.get(cloned.root?.right)).toBe('c');
|
|
1364
1364
|
});
|
|
1365
1365
|
|
|
1366
|
-
it('
|
|
1366
|
+
it('keys(): iterator yields keys in-order', () => {
|
|
1367
1367
|
const keys = binaryTree.keys();
|
|
1368
1368
|
expect([...keys]).toEqual([2, 1, 3]);
|
|
1369
1369
|
});
|
|
1370
1370
|
|
|
1371
|
-
it('
|
|
1371
|
+
it('values(): iterator yields values in-order', () => {
|
|
1372
1372
|
const values = binaryTree.values();
|
|
1373
1373
|
expect([...values]).toEqual(['b', 'a', 'c']);
|
|
1374
1374
|
});
|
|
1375
1375
|
|
|
1376
|
-
it('
|
|
1376
|
+
it('leaves(): returns leaf keys; clear() => []', () => {
|
|
1377
1377
|
const leaves = binaryTree.leaves();
|
|
1378
1378
|
expect(leaves).toEqual([2, 3]);
|
|
1379
1379
|
binaryTree.clear();
|
|
1380
1380
|
expect(binaryTree.leaves()).toEqual([]);
|
|
1381
1381
|
});
|
|
1382
1382
|
|
|
1383
|
-
it('
|
|
1383
|
+
it('bfs(includeNull=true, no callback): yields undefined placeholders', () => {
|
|
1384
1384
|
const binTree = new BinaryTree();
|
|
1385
1385
|
binTree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
|
|
1386
1386
|
const bfsResult = binTree.bfs(undefined, undefined, undefined, true);
|
|
@@ -1403,7 +1403,7 @@ describe('BinaryTree iterative methods test', () => {
|
|
|
1403
1403
|
});
|
|
1404
1404
|
});
|
|
1405
1405
|
|
|
1406
|
-
describe('BinaryTree
|
|
1406
|
+
describe('BinaryTree (non-Map mode) - higher-order & iteration', () => {
|
|
1407
1407
|
let binaryTree: BinaryTree<number, string>;
|
|
1408
1408
|
beforeEach(() => {
|
|
1409
1409
|
binaryTree = new BinaryTree<number, string>([], { isMapMode: false });
|
|
@@ -1412,14 +1412,274 @@ describe('BinaryTree not map mode iterative methods test', () => {
|
|
|
1412
1412
|
binaryTree.add([3, 'c']);
|
|
1413
1413
|
});
|
|
1414
1414
|
|
|
1415
|
-
it('
|
|
1415
|
+
it('clone(): preserves structure and allows get() by node', () => {
|
|
1416
1416
|
const cloned = binaryTree.clone();
|
|
1417
1417
|
expect(cloned.root?.left?.key).toBe(2);
|
|
1418
1418
|
expect(cloned.get(cloned.root?.right)).toBe('c');
|
|
1419
1419
|
});
|
|
1420
1420
|
});
|
|
1421
1421
|
|
|
1422
|
-
describe('
|
|
1422
|
+
describe('Coverage boosters - merge/print/iterator/startNode/addMany-mismatch/delete-miss', () => {
|
|
1423
|
+
it('merge: merge another tree (Map mode)', () => {
|
|
1424
|
+
const a = new BinaryTree<number, string>(
|
|
1425
|
+
[
|
|
1426
|
+
[2, 'b'],
|
|
1427
|
+
[1, 'a']
|
|
1428
|
+
],
|
|
1429
|
+
{ isMapMode: true }
|
|
1430
|
+
);
|
|
1431
|
+
const b = new BinaryTree<number, string>(
|
|
1432
|
+
[
|
|
1433
|
+
[3, 'c'],
|
|
1434
|
+
[4, 'd']
|
|
1435
|
+
],
|
|
1436
|
+
{ isMapMode: true }
|
|
1437
|
+
);
|
|
1438
|
+
a.merge(b);
|
|
1439
|
+
expect(a.size).toBe(4);
|
|
1440
|
+
expect(a.get(3)).toBe('c');
|
|
1441
|
+
expect(a.get(4)).toBe('d');
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
it('print: cover console.log branch (invokes toVisual)', () => {
|
|
1445
|
+
const t = new BinaryTree<number>([4, 2, 6, 1, 3]);
|
|
1446
|
+
const spy = jest.spyOn(console, 'log').mockImplementation(() => void 0);
|
|
1447
|
+
t.print({ isShowNull: true } as any, t.root);
|
|
1448
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
1449
|
+
const out: string = (spy.mock.calls[0]?.[0] as string) ?? '';
|
|
1450
|
+
expect(out.includes('N for null')).toBe(true);
|
|
1451
|
+
spy.mockRestore();
|
|
1452
|
+
});
|
|
1453
|
+
|
|
1454
|
+
it('for...of: trigger [Symbol.iterator] path (IterableEntryBase)', () => {
|
|
1455
|
+
const t = new BinaryTree<number, string>(
|
|
1456
|
+
[
|
|
1457
|
+
[1, 'x'],
|
|
1458
|
+
[2, 'y'],
|
|
1459
|
+
[3, 'z']
|
|
1460
|
+
],
|
|
1461
|
+
{ isMapMode: true } as any
|
|
1462
|
+
);
|
|
1463
|
+
const arr = Array.from(t); // like Array<[K, V | undefined]>
|
|
1464
|
+
const keys = arr.map(e => e?.[0]);
|
|
1465
|
+
const vals = arr.map(e => e?.[1]);
|
|
1466
|
+
expect(new Set(keys)).toEqual(new Set([1, 2, 3]));
|
|
1467
|
+
expect(new Set(vals)).toEqual(new Set(['x', 'y', 'z']));
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
it('startNode restricted to subtree: hits only within subtree', () => {
|
|
1471
|
+
const t = new BinaryTree<number, string>([
|
|
1472
|
+
[4, 'd'],
|
|
1473
|
+
[2, 'b'],
|
|
1474
|
+
[6, 'f'],
|
|
1475
|
+
[1, 'a'],
|
|
1476
|
+
[3, 'c']
|
|
1477
|
+
]);
|
|
1478
|
+
const sub = t.getNode(2)!; // subtree {2,1,3}
|
|
1479
|
+
// search 6 in subtree rooted at 2 -> miss
|
|
1480
|
+
expect(t.search(6, true, n => (n ? n.key : undefined), sub)).toEqual([]);
|
|
1481
|
+
// search 3 -> hit
|
|
1482
|
+
expect(t.search(3, true, n => (n ? n.key : undefined), sub)).toEqual([3]);
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
it('addMany: edge cases when values iterator shorter/longer than keys', () => {
|
|
1486
|
+
const t = new BinaryTree<number, number>([], { isMapMode: true } as any);
|
|
1487
|
+
// values has only 1 item, keys has 3
|
|
1488
|
+
t.addMany([1, 2, 3], [10]);
|
|
1489
|
+
expect(t.get(1)).toBe(10);
|
|
1490
|
+
expect(t.get(2)).toBeUndefined(); // subsequent value not provided
|
|
1491
|
+
expect(t.get(3)).toBeUndefined();
|
|
1492
|
+
|
|
1493
|
+
// reverse test: values longer (extra values should be ignored)
|
|
1494
|
+
const t2 = new BinaryTree<number, number>([], { isMapMode: true } as any);
|
|
1495
|
+
t2.addMany([7, 8], [70, 80, 90, 100]);
|
|
1496
|
+
expect(t2.get(7)).toBe(70);
|
|
1497
|
+
expect(t2.get(8)).toBe(80);
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
it('delete non-existent key: returns empty array and does not affect size', () => {
|
|
1501
|
+
const t = new BinaryTree<number>([1, 2, 3]);
|
|
1502
|
+
const before = t.size;
|
|
1503
|
+
const res = t.delete(999);
|
|
1504
|
+
expect(Array.isArray(res)).toBe(true);
|
|
1505
|
+
expect(res.length).toBe(0);
|
|
1506
|
+
expect(t.size).toBe(before);
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
it('toVisual additional combinations (S only / U only)', () => {
|
|
1510
|
+
const t = new BinaryTree<number>([2, 1, 3]);
|
|
1511
|
+
const sOnly = t.toVisual(t.root, { isShowRedBlackNIL: true } as any);
|
|
1512
|
+
const uOnly = t.toVisual(t.root, { isShowUndefined: true } as any);
|
|
1513
|
+
expect(sOnly.includes('S for Sentinel Node')).toBe(true);
|
|
1514
|
+
expect(uOnly.startsWith('U for undefined')).toBe(true);
|
|
1515
|
+
});
|
|
1516
|
+
|
|
1517
|
+
it('clone in Map mode shares storage: updates in original visible in clone', () => {
|
|
1518
|
+
const t = new BinaryTree<number, string>(
|
|
1519
|
+
[
|
|
1520
|
+
[1, 'a'],
|
|
1521
|
+
[2, 'b']
|
|
1522
|
+
],
|
|
1523
|
+
{ isMapMode: true } as any
|
|
1524
|
+
);
|
|
1525
|
+
const c = t.clone() as BinaryTree<number, string>;
|
|
1526
|
+
// In the original tree, "replace" the value for the same key (Map mode triggers _store.set)
|
|
1527
|
+
t.add([2, 'B']);
|
|
1528
|
+
// Because clone shares Map storage, the clone can also read the new value
|
|
1529
|
+
expect(c.get(2)).toBe('B');
|
|
1530
|
+
});
|
|
1531
|
+
});
|
|
1532
|
+
|
|
1533
|
+
// === [Coverage boosters - appended at end of file] ===
|
|
1534
|
+
|
|
1535
|
+
describe('Coverage boosters - close remaining uncovered branches', () => {
|
|
1536
|
+
it('print(): omit all params -> hit default startNode branch', () => {
|
|
1537
|
+
const t = new BinaryTree<number>([2, 1, 3]);
|
|
1538
|
+
const spy = jest.spyOn(console, 'log').mockImplementation(() => void 0);
|
|
1539
|
+
t.print(); // Use default arguments to cover the branch startNode = this._root
|
|
1540
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
1541
|
+
spy.mockRestore();
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
it('toVisual(): cover default args and empty-tree early return', () => {
|
|
1545
|
+
const t1 = new BinaryTree<number>([2, 1, 3]);
|
|
1546
|
+
const out1 = t1.toVisual(); // default startNode / options
|
|
1547
|
+
expect(typeof out1).toBe('string');
|
|
1548
|
+
|
|
1549
|
+
const t2 = new BinaryTree<number>(); // empty tree
|
|
1550
|
+
expect(t2.toVisual()).toBe(''); // no root after ensureNode -> directly return empty string
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
it('for...of (non-Map mode): hit else branch yielding [key, value]', () => {
|
|
1554
|
+
// default isMapMode=false
|
|
1555
|
+
const t = new BinaryTree<number, string>([
|
|
1556
|
+
[1, 'a'],
|
|
1557
|
+
[2, 'b']
|
|
1558
|
+
]);
|
|
1559
|
+
const got = Array.from(t); // Iterator runs in non-Map mode
|
|
1560
|
+
expect(got).toContainEqual([1, 'a']);
|
|
1561
|
+
expect(got).toContainEqual([2, 'b']);
|
|
1562
|
+
});
|
|
1563
|
+
|
|
1564
|
+
it('listLevels(): cover default args + RECURSIVE + includeNull=true', () => {
|
|
1565
|
+
// Level-order initialization with nulls to observe includeNull branch
|
|
1566
|
+
const t = new BinaryTree<number>([4, 2, 6, null, 3]);
|
|
1567
|
+
const levelsDefault = t.listLevels() as any; // default callback/startNode/iterationType
|
|
1568
|
+
expect(Array.isArray(levelsDefault)).toBe(true);
|
|
1569
|
+
|
|
1570
|
+
// enable includeNull=true (recursive branch)
|
|
1571
|
+
const levelsWithNulls = t.listLevels(n => (n ? n.key : null), undefined, 'RECURSIVE', true);
|
|
1572
|
+
const hasNull = levelsWithNulls.some(level => level.some(x => x === null));
|
|
1573
|
+
expect(hasNull).toBe(true);
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
it('map(options): pass options to cover _speciesCreate(options) path', () => {
|
|
1577
|
+
const t = new BinaryTree<number, string>([
|
|
1578
|
+
[1, 'a'],
|
|
1579
|
+
[2, 'b']
|
|
1580
|
+
]);
|
|
1581
|
+
const mapped = t.map((k, v) => [String(k), (v ?? '').toUpperCase()], { iterationType: 'RECURSIVE' } as any);
|
|
1582
|
+
expect(Array.from(mapped)).toEqual([
|
|
1583
|
+
['1', 'A'],
|
|
1584
|
+
['2', 'B']
|
|
1585
|
+
]);
|
|
1586
|
+
});
|
|
1587
|
+
|
|
1588
|
+
it('add(): build tree with no undefined child slot -> return false path', () => {
|
|
1589
|
+
const t = new BinaryTree<number>();
|
|
1590
|
+
const r = t._createNode(1)!;
|
|
1591
|
+
// explicitly set left/right child pointers to null (not undefined) so BFS finds no insertion slot
|
|
1592
|
+
(r as any).left = null;
|
|
1593
|
+
(r as any).right = null;
|
|
1594
|
+
(t as any)._root = r;
|
|
1595
|
+
(t as any)._size = 1;
|
|
1596
|
+
|
|
1597
|
+
expect(t.add(2)).toBe(false); // no insertion position -> return false
|
|
1598
|
+
});
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1601
|
+
// === [Coverage Boosters #2 - append below] ===
|
|
1602
|
+
describe('Coverage boosters v2 - hit remaining statements', () => {
|
|
1603
|
+
it('BinaryTreeNode.familyPosition -> MAL_NODE when parent does not point back', () => {
|
|
1604
|
+
const parent = new BinaryTreeNode<number>(1);
|
|
1605
|
+
const child = new BinaryTreeNode<number>(2);
|
|
1606
|
+
(child as any).parent = parent; // one-way parent assignment; parent does not attach child as left/right
|
|
1607
|
+
expect(child.familyPosition).toBe('MAL_NODE');
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
it('add(): returns false when tree has no undefined slots (all defined as null)', () => {
|
|
1611
|
+
const t = new BinaryTree<number>();
|
|
1612
|
+
const root = new BinaryTreeNode<number>(1);
|
|
1613
|
+
(root as any).left = null;
|
|
1614
|
+
(root as any).right = null;
|
|
1615
|
+
(t as any)._root = root;
|
|
1616
|
+
(t as any)._size = 1;
|
|
1617
|
+
expect(t.add(2)).toBe(false); // no slot with left/right undefined after queue traversal
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1620
|
+
it('getSuccessor(): climb ancestors while x is a right child', () => {
|
|
1621
|
+
const t = new BinaryTree<number>();
|
|
1622
|
+
const a = new BinaryTreeNode<number>(1);
|
|
1623
|
+
const b = new BinaryTreeNode<number>(2);
|
|
1624
|
+
const c = new BinaryTreeNode<number>(3);
|
|
1625
|
+
(t as any)._root = a;
|
|
1626
|
+
a.right = b;
|
|
1627
|
+
(b as any).parent = a;
|
|
1628
|
+
b.right = c;
|
|
1629
|
+
(c as any).parent = b;
|
|
1630
|
+
expect(t.getSuccessor(c)).toBe(undefined); // trigger multiple climbs in while (x === y.right)
|
|
1631
|
+
});
|
|
1632
|
+
|
|
1633
|
+
it('getPredecessor(): walk to right-most of left subtree', () => {
|
|
1634
|
+
const t = new BinaryTree<number>();
|
|
1635
|
+
const n5 = new BinaryTreeNode<number>(5);
|
|
1636
|
+
const n3 = new BinaryTreeNode<number>(3);
|
|
1637
|
+
const n4 = new BinaryTreeNode<number>(4);
|
|
1638
|
+
(t as any)._root = n5;
|
|
1639
|
+
n5.left = n3;
|
|
1640
|
+
(n3 as any).parent = n5;
|
|
1641
|
+
n3.right = n4;
|
|
1642
|
+
(n4 as any).parent = n3;
|
|
1643
|
+
expect(t.getPredecessor(n5)).toBe(n4); // hit the while loop
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
it('_extractKey via Map mode: get/has on entry tuple + null/undefined keys', () => {
|
|
1647
|
+
const t = new BinaryTree<number, string>([], { isMapMode: true } as any);
|
|
1648
|
+
t.add([1, 'a']);
|
|
1649
|
+
t.add([2, 'b']);
|
|
1650
|
+
expect(t.get([2, 'anything'] as any)).toBe('b'); // entry tuple path
|
|
1651
|
+
expect(t.has([1, 'x'] as any)).toBe(true);
|
|
1652
|
+
expect(t.get([null as any, 'x'] as any)).toBeUndefined(); // null key
|
|
1653
|
+
expect(t.get([undefined as any, 'x'] as any)).toBeUndefined(); // undefined key
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
it('_setValue: value is undefined branch executes (Map mode)', () => {
|
|
1657
|
+
const t = new BinaryTree<number, string>([], { isMapMode: true } as any);
|
|
1658
|
+
expect(t.add([10, undefined] as any)).toBe(true); // trigger _setValue branch where value is undefined
|
|
1659
|
+
expect(t.get(10)).toBeUndefined();
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
it('print(): default-args branch (no params)', () => {
|
|
1663
|
+
const t = new BinaryTree<number>([2, 1, 3]);
|
|
1664
|
+
const spy = jest.spyOn(console, 'log').mockImplementation(() => void 0);
|
|
1665
|
+
t.print(); // no arguments -> hit default startNode branch
|
|
1666
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
1667
|
+
spy.mockRestore();
|
|
1668
|
+
});
|
|
1669
|
+
|
|
1670
|
+
it('search(undefined): returns [] (early return)', () => {
|
|
1671
|
+
const t = new BinaryTree<number>([1, 2, 3]);
|
|
1672
|
+
expect(t.search(undefined as any)).toEqual([]);
|
|
1673
|
+
expect(t.search(null as any)).toEqual([]);
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
it('isValidKey(null): returns true', () => {
|
|
1677
|
+
const t = new BinaryTree<number>();
|
|
1678
|
+
expect(t.isValidKey(null)).toBe(true);
|
|
1679
|
+
});
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
describe('Classic usage examples', () => {
|
|
1423
1683
|
it('@example determine loan approval using a decision tree', () => {
|
|
1424
1684
|
// Decision tree structure
|
|
1425
1685
|
const loanDecisionTree = new BinaryTree<string>(
|