data-structure-typed 2.0.5 → 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 +1 -1
- package/COMMANDS.md +17 -0
- package/benchmark/report.html +13 -77
- package/benchmark/report.json +145 -177
- 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 +594 -865
- 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 +1 -0
- package/dist/cjs/utils/utils.d.ts +1 -1
- package/dist/cjs/utils/utils.js +2 -1
- 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 +598 -874
- 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 +1 -0
- package/dist/esm/utils/utils.d.ts +1 -1
- package/dist/esm/utils/utils.js +2 -1
- package/dist/esm/utils/utils.js.map +1 -1
- package/dist/umd/data-structure-typed.js +4685 -6477
- 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 +660 -889
- 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 +2 -0
- package/src/utils/utils.ts +9 -14
- 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 +12 -9
- 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
|
@@ -10,30 +10,40 @@ import { Queue } from '../queue';
|
|
|
10
10
|
import { IterableEntryBase } from '../base';
|
|
11
11
|
import { DFSOperation, Range } from '../../common';
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @template V - The type of
|
|
15
|
-
* @template BinaryTreeNode<K, V> - The type of the family relationship in the binary tree.
|
|
13
|
+
* @template K - The type of the key.
|
|
14
|
+
* @template V - The type of the value.
|
|
16
15
|
*/
|
|
17
16
|
export class BinaryTreeNode {
|
|
18
17
|
key;
|
|
19
18
|
value;
|
|
20
19
|
parent = undefined;
|
|
21
20
|
/**
|
|
22
|
-
*
|
|
23
|
-
* @
|
|
24
|
-
*
|
|
25
|
-
* @param
|
|
26
|
-
*
|
|
27
|
-
* default to `undefined`.
|
|
21
|
+
* Creates an instance of BinaryTreeNode.
|
|
22
|
+
* @remarks Time O(1), Space O(1)
|
|
23
|
+
*
|
|
24
|
+
* @param key - The key of the node.
|
|
25
|
+
* @param [value] - The value associated with the key.
|
|
28
26
|
*/
|
|
29
27
|
constructor(key, value) {
|
|
30
28
|
this.key = key;
|
|
31
29
|
this.value = value;
|
|
32
30
|
}
|
|
33
31
|
_left = undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Gets the left child of the node.
|
|
34
|
+
* @remarks Time O(1), Space O(1)
|
|
35
|
+
*
|
|
36
|
+
* @returns The left child.
|
|
37
|
+
*/
|
|
34
38
|
get left() {
|
|
35
39
|
return this._left;
|
|
36
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Sets the left child of the node and updates its parent reference.
|
|
43
|
+
* @remarks Time O(1), Space O(1)
|
|
44
|
+
*
|
|
45
|
+
* @param v - The node to set as the left child.
|
|
46
|
+
*/
|
|
37
47
|
set left(v) {
|
|
38
48
|
if (v) {
|
|
39
49
|
v.parent = this;
|
|
@@ -41,9 +51,21 @@ export class BinaryTreeNode {
|
|
|
41
51
|
this._left = v;
|
|
42
52
|
}
|
|
43
53
|
_right = undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Gets the right child of the node.
|
|
56
|
+
* @remarks Time O(1), Space O(1)
|
|
57
|
+
*
|
|
58
|
+
* @returns The right child.
|
|
59
|
+
*/
|
|
44
60
|
get right() {
|
|
45
61
|
return this._right;
|
|
46
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Sets the right child of the node and updates its parent reference.
|
|
65
|
+
* @remarks Time O(1), Space O(1)
|
|
66
|
+
*
|
|
67
|
+
* @param v - The node to set as the right child.
|
|
68
|
+
*/
|
|
47
69
|
set right(v) {
|
|
48
70
|
if (v) {
|
|
49
71
|
v.parent = this;
|
|
@@ -51,26 +73,68 @@ export class BinaryTreeNode {
|
|
|
51
73
|
this._right = v;
|
|
52
74
|
}
|
|
53
75
|
_height = 0;
|
|
76
|
+
/**
|
|
77
|
+
* Gets the height of the node (used in self-balancing trees).
|
|
78
|
+
* @remarks Time O(1), Space O(1)
|
|
79
|
+
*
|
|
80
|
+
* @returns The height.
|
|
81
|
+
*/
|
|
54
82
|
get height() {
|
|
55
83
|
return this._height;
|
|
56
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Sets the height of the node.
|
|
87
|
+
* @remarks Time O(1), Space O(1)
|
|
88
|
+
*
|
|
89
|
+
* @param value - The new height.
|
|
90
|
+
*/
|
|
57
91
|
set height(value) {
|
|
58
92
|
this._height = value;
|
|
59
93
|
}
|
|
60
94
|
_color = 'BLACK';
|
|
95
|
+
/**
|
|
96
|
+
* Gets the color of the node (used in Red-Black trees).
|
|
97
|
+
* @remarks Time O(1), Space O(1)
|
|
98
|
+
*
|
|
99
|
+
* @returns The node's color.
|
|
100
|
+
*/
|
|
61
101
|
get color() {
|
|
62
102
|
return this._color;
|
|
63
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Sets the color of the node.
|
|
106
|
+
* @remarks Time O(1), Space O(1)
|
|
107
|
+
*
|
|
108
|
+
* @param value - The new color.
|
|
109
|
+
*/
|
|
64
110
|
set color(value) {
|
|
65
111
|
this._color = value;
|
|
66
112
|
}
|
|
67
113
|
_count = 1;
|
|
114
|
+
/**
|
|
115
|
+
* Gets the count of nodes in the subtree rooted at this node (used in order-statistic trees).
|
|
116
|
+
* @remarks Time O(1), Space O(1)
|
|
117
|
+
*
|
|
118
|
+
* @returns The subtree node count.
|
|
119
|
+
*/
|
|
68
120
|
get count() {
|
|
69
121
|
return this._count;
|
|
70
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Sets the count of nodes in the subtree.
|
|
125
|
+
* @remarks Time O(1), Space O(1)
|
|
126
|
+
*
|
|
127
|
+
* @param value - The new count.
|
|
128
|
+
*/
|
|
71
129
|
set count(value) {
|
|
72
130
|
this._count = value;
|
|
73
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Gets the position of the node relative to its parent.
|
|
134
|
+
* @remarks Time O(1), Space O(1)
|
|
135
|
+
*
|
|
136
|
+
* @returns The family position (e.g., 'ROOT', 'LEFT', 'RIGHT').
|
|
137
|
+
*/
|
|
74
138
|
get familyPosition() {
|
|
75
139
|
if (!this.parent) {
|
|
76
140
|
return this.left || this.right ? 'ROOT' : 'ISOLATED';
|
|
@@ -85,6 +149,15 @@ export class BinaryTreeNode {
|
|
|
85
149
|
}
|
|
86
150
|
}
|
|
87
151
|
/**
|
|
152
|
+
* A general Binary Tree implementation.
|
|
153
|
+
*
|
|
154
|
+
* @remarks
|
|
155
|
+
* This class implements a basic Binary Tree, not a Binary Search Tree.
|
|
156
|
+
* The `add` operation inserts nodes level-by-level (BFS) into the first available slot.
|
|
157
|
+
*
|
|
158
|
+
* @template K - The type of the key.
|
|
159
|
+
* @template V - The type of the value.
|
|
160
|
+
* @template R - The type of the raw data object (if using `toEntryFn`).
|
|
88
161
|
* 1. Two Children Maximum: Each node has at most two children.
|
|
89
162
|
* 2. Left and Right Children: Nodes have distinct left and right children.
|
|
90
163
|
* 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree.
|
|
@@ -156,13 +229,11 @@ export class BinaryTreeNode {
|
|
|
156
229
|
export class BinaryTree extends IterableEntryBase {
|
|
157
230
|
iterationType = 'ITERATIVE';
|
|
158
231
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* @param [options] - The `options` parameter in the constructor is an optional object that can
|
|
165
|
-
* contain the following properties:
|
|
232
|
+
* Creates an instance of BinaryTree.
|
|
233
|
+
* @remarks Time O(N * M), where N is the number of items in `keysNodesEntriesOrRaws` and M is the tree size at insertion time (due to O(M) `add` operation). Space O(N) for storing the nodes.
|
|
234
|
+
*
|
|
235
|
+
* @param [keysNodesEntriesOrRaws=[]] - An iterable of items to add.
|
|
236
|
+
* @param [options] - Configuration options for the tree.
|
|
166
237
|
*/
|
|
167
238
|
constructor(keysNodesEntriesOrRaws = [], options) {
|
|
168
239
|
super();
|
|
@@ -183,81 +254,103 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
183
254
|
this.addMany(keysNodesEntriesOrRaws);
|
|
184
255
|
}
|
|
185
256
|
_isMapMode = true;
|
|
257
|
+
/**
|
|
258
|
+
* Gets whether the tree is in Map mode.
|
|
259
|
+
* @remarks In Map mode (default), values are stored in an external Map, and nodes only hold keys. If false, values are stored directly on the nodes. Time O(1)
|
|
260
|
+
*
|
|
261
|
+
* @returns True if in Map mode, false otherwise.
|
|
262
|
+
*/
|
|
186
263
|
get isMapMode() {
|
|
187
264
|
return this._isMapMode;
|
|
188
265
|
}
|
|
189
266
|
_isDuplicate = false;
|
|
267
|
+
/**
|
|
268
|
+
* Gets whether the tree allows duplicate keys.
|
|
269
|
+
* @remarks Time O(1)
|
|
270
|
+
*
|
|
271
|
+
* @returns True if duplicates are allowed, false otherwise.
|
|
272
|
+
*/
|
|
190
273
|
get isDuplicate() {
|
|
191
274
|
return this._isDuplicate;
|
|
192
275
|
}
|
|
193
276
|
_store = new Map();
|
|
277
|
+
/**
|
|
278
|
+
* Gets the external value store (used in Map mode).
|
|
279
|
+
* @remarks Time O(1)
|
|
280
|
+
*
|
|
281
|
+
* @returns The map storing key-value pairs.
|
|
282
|
+
*/
|
|
194
283
|
get store() {
|
|
195
284
|
return this._store;
|
|
196
285
|
}
|
|
197
286
|
_root;
|
|
287
|
+
/**
|
|
288
|
+
* Gets the root node of the tree.
|
|
289
|
+
* @remarks Time O(1)
|
|
290
|
+
*
|
|
291
|
+
* @returns The root node.
|
|
292
|
+
*/
|
|
198
293
|
get root() {
|
|
199
294
|
return this._root;
|
|
200
295
|
}
|
|
201
296
|
_size = 0;
|
|
297
|
+
/**
|
|
298
|
+
* Gets the number of nodes in the tree.
|
|
299
|
+
* @remarks Time O(1)
|
|
300
|
+
*
|
|
301
|
+
* @returns The size of the tree.
|
|
302
|
+
*/
|
|
202
303
|
get size() {
|
|
203
304
|
return this._size;
|
|
204
305
|
}
|
|
205
306
|
_NIL = new BinaryTreeNode(NaN);
|
|
307
|
+
/**
|
|
308
|
+
* Gets the sentinel NIL node (used in self-balancing trees like Red-Black Tree).
|
|
309
|
+
* @remarks Time O(1)
|
|
310
|
+
*
|
|
311
|
+
* @returns The NIL node.
|
|
312
|
+
*/
|
|
206
313
|
get NIL() {
|
|
207
314
|
return this._NIL;
|
|
208
315
|
}
|
|
209
316
|
_toEntryFn;
|
|
317
|
+
/**
|
|
318
|
+
* Gets the function used to convert raw data objects (R) into [key, value] entries.
|
|
319
|
+
* @remarks Time O(1)
|
|
320
|
+
*
|
|
321
|
+
* @returns The conversion function.
|
|
322
|
+
*/
|
|
210
323
|
get toEntryFn() {
|
|
211
324
|
return this._toEntryFn;
|
|
212
325
|
}
|
|
213
326
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
327
|
+
* (Protected) Creates a new node.
|
|
328
|
+
* @remarks Time O(1), Space O(1)
|
|
216
329
|
*
|
|
217
|
-
* The
|
|
218
|
-
* @param
|
|
219
|
-
* @
|
|
220
|
-
* not required to be provided when calling the function. If a `value` is provided, it should be of
|
|
221
|
-
* type `V`, which is the type of the value associated with the node.
|
|
222
|
-
* @returns A new BinaryTreeNode instance with the provided key and value is being returned, casted
|
|
223
|
-
* as BinaryTreeNode<K, V>.
|
|
330
|
+
* @param key - The key for the new node.
|
|
331
|
+
* @param [value] - The value for the new node (used if not in Map mode).
|
|
332
|
+
* @returns The newly created node.
|
|
224
333
|
*/
|
|
225
|
-
|
|
334
|
+
_createNode(key, value) {
|
|
226
335
|
return new BinaryTreeNode(key, this._isMapMode ? undefined : value);
|
|
227
336
|
}
|
|
228
337
|
/**
|
|
229
|
-
*
|
|
230
|
-
*
|
|
338
|
+
* Creates a new, empty tree of the same type and configuration.
|
|
339
|
+
* @remarks Time O(1) (excluding options cloning), Space O(1)
|
|
231
340
|
*
|
|
232
|
-
*
|
|
233
|
-
* @
|
|
234
|
-
* that allows you to provide partial configuration options for creating a binary tree. It is of type
|
|
235
|
-
* `Partial<BinaryTreeOptions<K, V, R>>`, which means you can pass in an object containing a subset
|
|
236
|
-
* of properties
|
|
237
|
-
* @returns A new instance of a binary tree with the specified options is being returned.
|
|
341
|
+
* @param [options] - Optional overrides for the new tree's options.
|
|
342
|
+
* @returns A new, empty tree instance.
|
|
238
343
|
*/
|
|
239
344
|
createTree(options) {
|
|
240
|
-
return
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
*
|
|
249
|
-
* Space Complexity: O(log n)
|
|
250
|
-
*
|
|
251
|
-
* The function `ensureNode` in TypeScript checks if a given input is a node, entry, key, or raw
|
|
252
|
-
* value and returns the corresponding node or null.
|
|
253
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
|
254
|
-
* parameter in the `ensureNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It
|
|
255
|
-
* is used to determine whether the input is a key, node, entry, or raw data. The
|
|
256
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `ensureNode` function
|
|
257
|
-
* is used to specify the type of iteration to be performed. It has a default value of
|
|
258
|
-
* `this.iterationType` if not explicitly provided.
|
|
259
|
-
* @returns The `ensureNode` function returns either a node, `null`, or `undefined` based on the
|
|
260
|
-
* conditions specified in the code snippet.
|
|
345
|
+
return this._createInstance(options);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Ensures the input is a node. If it's a key or entry, it searches for the node.
|
|
349
|
+
* @remarks Time O(1) if a node is passed. O(N) if a key or entry is passed (due to `getNode` performing a full search). Space O(1) if iterative search, O(H) if recursive (where H is height, O(N) worst-case).
|
|
350
|
+
*
|
|
351
|
+
* @param keyNodeOrEntry - The item to resolve to a node.
|
|
352
|
+
* @param [iterationType=this.iterationType] - The traversal method to use if searching.
|
|
353
|
+
* @returns The resolved node, or null/undefined if not found or input is null/undefined.
|
|
261
354
|
*/
|
|
262
355
|
ensureNode(keyNodeOrEntry, iterationType = this.iterationType) {
|
|
263
356
|
if (keyNodeOrEntry === null)
|
|
@@ -279,47 +372,31 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
279
372
|
return this.getNode(keyNodeOrEntry, this._root, iterationType);
|
|
280
373
|
}
|
|
281
374
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
375
|
+
* Checks if the given item is a `BinaryTreeNode` instance.
|
|
376
|
+
* @remarks Time O(1), Space O(1)
|
|
284
377
|
*
|
|
285
|
-
*
|
|
286
|
-
* @
|
|
287
|
-
* `keyNodeOrEntry` can be either a key, a node, an entry, or raw data. The function is
|
|
288
|
-
* checking if the input is an instance of a `BinaryTreeNode` and returning a boolean value
|
|
289
|
-
* accordingly.
|
|
290
|
-
* @returns The function `isNode` is checking if the input `keyNodeOrEntry` is an instance of
|
|
291
|
-
* `BinaryTreeNode`. If it is, the function returns `true`, indicating that the input is a node. If
|
|
292
|
-
* it is not an instance of `BinaryTreeNode`, the function returns `false`, indicating that the input
|
|
293
|
-
* is not a node.
|
|
378
|
+
* @param keyNodeOrEntry - The item to check.
|
|
379
|
+
* @returns True if it's a node, false otherwise.
|
|
294
380
|
*/
|
|
295
381
|
isNode(keyNodeOrEntry) {
|
|
296
382
|
return keyNodeOrEntry instanceof BinaryTreeNode;
|
|
297
383
|
}
|
|
298
384
|
/**
|
|
299
|
-
*
|
|
300
|
-
*
|
|
385
|
+
* Checks if the given item is a raw data object (R) that needs conversion via `toEntryFn`.
|
|
386
|
+
* @remarks Time O(1), Space O(1)
|
|
301
387
|
*
|
|
302
|
-
*
|
|
303
|
-
* @
|
|
304
|
-
* @returns The function `isRaw` is checking if the `keyNodeEntryOrRaw` parameter is of type `R` by
|
|
305
|
-
* checking if it is an object. If the parameter is an object, the function will return `true`,
|
|
306
|
-
* indicating that it is of type `R`.
|
|
388
|
+
* @param keyNodeEntryOrRaw - The item to check.
|
|
389
|
+
* @returns True if it's a raw object, false otherwise.
|
|
307
390
|
*/
|
|
308
391
|
isRaw(keyNodeEntryOrRaw) {
|
|
309
392
|
return this._toEntryFn !== undefined && typeof keyNodeEntryOrRaw === 'object';
|
|
310
393
|
}
|
|
311
394
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
395
|
+
* Checks if the given item is a "real" node (i.e., not null, undefined, or NIL).
|
|
396
|
+
* @remarks Time O(1), Space O(1)
|
|
314
397
|
*
|
|
315
|
-
*
|
|
316
|
-
* @
|
|
317
|
-
* parameter in the `isRealNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
|
|
318
|
-
* The function checks if the input parameter is a `BinaryTreeNode<K, V>` type by verifying if it is not equal
|
|
319
|
-
* @returns The function `isRealNode` is checking if the input `keyNodeOrEntry` is a valid
|
|
320
|
-
* node by comparing it to `this._NIL`, `null`, and `undefined`. If the input is not one of these
|
|
321
|
-
* values, it then calls the `isNode` method to further determine if the input is a node. The
|
|
322
|
-
* function will return a boolean value indicating whether the
|
|
398
|
+
* @param keyNodeOrEntry - The item to check.
|
|
399
|
+
* @returns True if it's a real node, false otherwise.
|
|
323
400
|
*/
|
|
324
401
|
isRealNode(keyNodeOrEntry) {
|
|
325
402
|
if (keyNodeOrEntry === this._NIL || keyNodeOrEntry === null || keyNodeOrEntry === undefined)
|
|
@@ -327,97 +404,66 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
327
404
|
return this.isNode(keyNodeOrEntry);
|
|
328
405
|
}
|
|
329
406
|
/**
|
|
330
|
-
*
|
|
331
|
-
*
|
|
407
|
+
* Checks if the given item is either a "real" node or null.
|
|
408
|
+
* @remarks Time O(1), Space O(1)
|
|
332
409
|
*
|
|
333
|
-
*
|
|
334
|
-
* @
|
|
335
|
-
* `keyNodeOrEntry` in the `isRealNodeOrNull` function can be of type `BTNRep<K,
|
|
336
|
-
* V, BinaryTreeNode<K, V>>` or `R`. It is a union type that can either be a key, a node, an entry, or
|
|
337
|
-
* @returns The function `isRealNodeOrNull` is returning a boolean value. It checks if the input
|
|
338
|
-
* `keyNodeOrEntry` is either `null` or a real node, and returns `true` if it is a node or
|
|
339
|
-
* `null`, and `false` otherwise.
|
|
410
|
+
* @param keyNodeOrEntry - The item to check.
|
|
411
|
+
* @returns True if it's a real node or null, false otherwise.
|
|
340
412
|
*/
|
|
341
413
|
isRealNodeOrNull(keyNodeOrEntry) {
|
|
342
414
|
return keyNodeOrEntry === null || this.isRealNode(keyNodeOrEntry);
|
|
343
415
|
}
|
|
344
416
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
417
|
+
* Checks if the given item is the sentinel NIL node.
|
|
418
|
+
* @remarks Time O(1), Space O(1)
|
|
347
419
|
*
|
|
348
|
-
*
|
|
349
|
-
* @
|
|
350
|
-
* BinaryTreeNode<K, V>>
|
|
351
|
-
* @returns The function is checking if the `keyNodeOrEntry` parameter is equal to the `_NIL`
|
|
352
|
-
* property of the current object and returning a boolean value based on that comparison.
|
|
420
|
+
* @param keyNodeOrEntry - The item to check.
|
|
421
|
+
* @returns True if it's the NIL node, false otherwise.
|
|
353
422
|
*/
|
|
354
423
|
isNIL(keyNodeOrEntry) {
|
|
355
424
|
return keyNodeOrEntry === this._NIL;
|
|
356
425
|
}
|
|
357
426
|
/**
|
|
358
|
-
*
|
|
359
|
-
*
|
|
427
|
+
* Checks if the given item is a `Range` object.
|
|
428
|
+
* @remarks Time O(1), Space O(1)
|
|
360
429
|
*
|
|
361
|
-
*
|
|
362
|
-
* @
|
|
363
|
-
* - The `keyNodeEntryOrPredicate` parameter in the `isRange` function can be
|
|
364
|
-
* of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `NodePredicate<BinaryTreeNode<K, V>>`, or
|
|
365
|
-
* `Range<K>`. The function checks if the `keyNodeEntry
|
|
366
|
-
* @returns The `isRange` function is checking if the `keyNodeEntryOrPredicate` parameter is an
|
|
367
|
-
* instance of the `Range` class. If it is an instance of `Range`, the function will return `true`,
|
|
368
|
-
* indicating that the parameter is a `Range<K>`. If it is not an instance of `Range`, the function
|
|
369
|
-
* will return `false`.
|
|
430
|
+
* @param keyNodeEntryOrPredicate - The item to check.
|
|
431
|
+
* @returns True if it's a Range, false otherwise.
|
|
370
432
|
*/
|
|
371
433
|
isRange(keyNodeEntryOrPredicate) {
|
|
372
434
|
return keyNodeEntryOrPredicate instanceof Range;
|
|
373
435
|
}
|
|
374
436
|
/**
|
|
375
|
-
*
|
|
376
|
-
*
|
|
437
|
+
* Checks if a node is a leaf (has no real children).
|
|
438
|
+
* @remarks Time O(N) if a key/entry is passed (due to `ensureNode`). O(1) if a node is passed. Space O(1) or O(H) (from `ensureNode`).
|
|
377
439
|
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
|
381
|
-
* `keyNodeOrEntry` can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It represents a
|
|
382
|
-
* key, node, entry, or raw data in a binary tree structure. The function `isLeaf` checks whether the
|
|
383
|
-
* provided
|
|
384
|
-
* @returns The function `isLeaf` returns a boolean value indicating whether the input
|
|
385
|
-
* `keyNodeOrEntry` is a leaf node in a binary tree.
|
|
440
|
+
* @param keyNodeOrEntry - The node to check.
|
|
441
|
+
* @returns True if the node is a leaf, false otherwise.
|
|
386
442
|
*/
|
|
387
443
|
isLeaf(keyNodeOrEntry) {
|
|
388
444
|
keyNodeOrEntry = this.ensureNode(keyNodeOrEntry);
|
|
389
445
|
if (keyNodeOrEntry === undefined)
|
|
390
446
|
return false;
|
|
391
447
|
if (keyNodeOrEntry === null)
|
|
392
|
-
return true;
|
|
448
|
+
return true; // A null spot is considered a leaf
|
|
393
449
|
return !this.isRealNode(keyNodeOrEntry.left) && !this.isRealNode(keyNodeOrEntry.right);
|
|
394
450
|
}
|
|
395
451
|
/**
|
|
396
|
-
*
|
|
397
|
-
*
|
|
452
|
+
* Checks if the given item is a [key, value] entry pair.
|
|
453
|
+
* @remarks Time O(1), Space O(1)
|
|
398
454
|
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
|
402
|
-
* parameter in the `isEntry` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or type `R`.
|
|
403
|
-
* The function checks if the provided `keyNodeOrEntry` is of type `BTN
|
|
404
|
-
* @returns The `isEntry` function is checking if the `keyNodeOrEntry` parameter is an array
|
|
405
|
-
* with a length of 2. If it is, then it returns `true`, indicating that the parameter is of type
|
|
406
|
-
* `BTNEntry<K, V>`. If the condition is not met, it returns `false`.
|
|
455
|
+
* @param keyNodeOrEntry - The item to check.
|
|
456
|
+
* @returns True if it's an entry, false otherwise.
|
|
407
457
|
*/
|
|
408
458
|
isEntry(keyNodeOrEntry) {
|
|
409
459
|
return Array.isArray(keyNodeOrEntry) && keyNodeOrEntry.length === 2;
|
|
410
460
|
}
|
|
411
461
|
/**
|
|
412
|
-
*
|
|
413
|
-
*
|
|
462
|
+
* Checks if the given key is valid (comparable or null).
|
|
463
|
+
* @remarks Time O(1), Space O(1)
|
|
414
464
|
*
|
|
415
|
-
*
|
|
416
|
-
* @
|
|
417
|
-
* TypeScript.
|
|
418
|
-
* @returns The function `isValidKey` is checking if the `key` parameter is `null` or if it is comparable.
|
|
419
|
-
* If the `key` is `null`, the function returns `true`. Otherwise, it returns the result of the
|
|
420
|
-
* `isComparable` function, which is not provided in the code snippet.
|
|
465
|
+
* @param key - The key to validate.
|
|
466
|
+
* @returns True if the key is valid, false otherwise.
|
|
421
467
|
*/
|
|
422
468
|
isValidKey(key) {
|
|
423
469
|
if (key === null)
|
|
@@ -425,27 +471,17 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
425
471
|
return isComparable(key);
|
|
426
472
|
}
|
|
427
473
|
/**
|
|
428
|
-
*
|
|
429
|
-
*
|
|
474
|
+
* Adds a new node to the tree.
|
|
475
|
+
* @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). This implementation adds the node at the first available position in a level-order (BFS) traversal. This is NOT a Binary Search Tree insertion. Time O(N), where N is the number of nodes. It must traverse level-by-level to find an empty slot. Space O(N) in the worst case for the BFS queue (e.g., a full last level).
|
|
430
476
|
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
* @
|
|
434
|
-
* seems to be for adding a new node to a binary tree structure. The `keyNodeOrEntry`
|
|
435
|
-
* parameter in the method can accept different types of values:
|
|
436
|
-
* @param {V} [value] - The `value` parameter in the `add` method represents the value associated
|
|
437
|
-
* with the key that you want to add to the binary tree. When adding a key-value pair to the binary
|
|
438
|
-
* tree, you provide the key and its corresponding value. The `add` method then creates a new node
|
|
439
|
-
* with this
|
|
440
|
-
* @returns The `add` method returns a boolean value. It returns `true` if the insertion of the new
|
|
441
|
-
* node was successful, and `false` if the insertion position could not be found or if a duplicate
|
|
442
|
-
* key was found and the node was replaced instead of inserted.
|
|
477
|
+
* @param keyNodeOrEntry - The key, node, or entry to add.
|
|
478
|
+
* @param [value] - The value, if providing just a key.
|
|
479
|
+
* @returns True if the addition was successful, false otherwise.
|
|
443
480
|
*/
|
|
444
481
|
add(keyNodeOrEntry, value) {
|
|
445
482
|
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
|
446
483
|
if (newNode === undefined)
|
|
447
484
|
return false;
|
|
448
|
-
// If the tree is empty, directly set the new node as the root node
|
|
449
485
|
if (!this._root) {
|
|
450
486
|
this._setRoot(newNode);
|
|
451
487
|
if (this._isMapMode)
|
|
@@ -454,25 +490,22 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
454
490
|
return true;
|
|
455
491
|
}
|
|
456
492
|
const queue = new Queue([this._root]);
|
|
457
|
-
let potentialParent;
|
|
493
|
+
let potentialParent;
|
|
458
494
|
while (queue.length > 0) {
|
|
459
495
|
const cur = queue.shift();
|
|
460
496
|
if (!cur)
|
|
461
497
|
continue;
|
|
462
498
|
if (!this._isDuplicate) {
|
|
463
|
-
// Check for duplicate keys when newNode is not null
|
|
464
499
|
if (newNode !== null && cur.key === newNode.key) {
|
|
465
500
|
this._replaceNode(cur, newNode);
|
|
466
501
|
if (this._isMapMode)
|
|
467
502
|
this._setValue(cur.key, newValue);
|
|
468
|
-
return true; //
|
|
503
|
+
return true; // Replaced existing node
|
|
469
504
|
}
|
|
470
505
|
}
|
|
471
|
-
// Record the first possible insertion location found
|
|
472
506
|
if (potentialParent === undefined && (cur.left === undefined || cur.right === undefined)) {
|
|
473
507
|
potentialParent = cur;
|
|
474
508
|
}
|
|
475
|
-
// Continue traversing the left and right subtrees
|
|
476
509
|
if (cur.left !== null) {
|
|
477
510
|
if (cur.left)
|
|
478
511
|
queue.push(cur.left);
|
|
@@ -482,7 +515,6 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
482
515
|
queue.push(cur.right);
|
|
483
516
|
}
|
|
484
517
|
}
|
|
485
|
-
// At the end of the traversal, if the insertion position is found, insert
|
|
486
518
|
if (potentialParent) {
|
|
487
519
|
if (potentialParent.left === undefined) {
|
|
488
520
|
potentialParent.left = newNode;
|
|
@@ -495,28 +527,17 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
495
527
|
this._size++;
|
|
496
528
|
return true;
|
|
497
529
|
}
|
|
498
|
-
return false; //
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
*
|
|
502
|
-
* Space
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
* each
|
|
507
|
-
* @param keysNodesEntriesOrRaws - `keysNodesEntriesOrRaws` is an iterable that can contain a
|
|
508
|
-
* mix of keys, nodes, entries, or raw values. Each element in this iterable can be of type
|
|
509
|
-
* `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
|
|
510
|
-
* @param [values] - The `values` parameter in the `addMany` function is an optional parameter that
|
|
511
|
-
* accepts an iterable of values. These values correspond to the keys or nodes being added in the
|
|
512
|
-
* `keysNodesEntriesOrRaws` parameter. If provided, the function will iterate over the values and
|
|
513
|
-
* assign them
|
|
514
|
-
* @returns The `addMany` method returns an array of boolean values indicating whether each key,
|
|
515
|
-
* node, entry, or raw value was successfully added to the data structure. Each boolean value
|
|
516
|
-
* corresponds to the success of adding the corresponding key or value in the input iterable.
|
|
530
|
+
return false; // Should not happen if tree is not full?
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Adds multiple items to the tree.
|
|
534
|
+
* @remarks Time O(N * M), where N is the number of items to add and M is the size of the tree at insertion (due to O(M) `add` operation). Space O(M) (from `add`) + O(N) (for the `inserted` array).
|
|
535
|
+
*
|
|
536
|
+
* @param keysNodesEntriesOrRaws - An iterable of items to add.
|
|
537
|
+
* @param [values] - An optional parallel iterable of values.
|
|
538
|
+
* @returns An array of booleans indicating the success of each individual `add` operation.
|
|
517
539
|
*/
|
|
518
540
|
addMany(keysNodesEntriesOrRaws, values) {
|
|
519
|
-
// TODO not sure addMany not be run multi times
|
|
520
541
|
const inserted = [];
|
|
521
542
|
let valuesIterator;
|
|
522
543
|
if (values) {
|
|
@@ -537,46 +558,31 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
537
558
|
return inserted;
|
|
538
559
|
}
|
|
539
560
|
/**
|
|
540
|
-
*
|
|
541
|
-
*
|
|
561
|
+
* Merges another tree into this one by adding all its nodes.
|
|
562
|
+
* @remarks Time O(N * M), same as `addMany`, where N is the size of `anotherTree` and M is the size of this tree. Space O(M) (from `add`).
|
|
542
563
|
*
|
|
543
|
-
*
|
|
544
|
-
* elements from the other tree.
|
|
545
|
-
* @param anotherTree - BinaryTree<K, V, R, MK, MV, MR>
|
|
564
|
+
* @param anotherTree - The tree to merge.
|
|
546
565
|
*/
|
|
547
566
|
merge(anotherTree) {
|
|
548
567
|
this.addMany(anotherTree, []);
|
|
549
568
|
}
|
|
550
569
|
/**
|
|
551
|
-
*
|
|
552
|
-
*
|
|
570
|
+
* Clears the tree and refills it with new items.
|
|
571
|
+
* @remarks Time O(N) (for `clear`) + O(N * M) (for `addMany`) = O(N * M). Space O(M) (from `addMany`).
|
|
553
572
|
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the `refill`
|
|
557
|
-
* method can accept an iterable containing a mix of `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` objects or `R`
|
|
558
|
-
* objects.
|
|
559
|
-
* @param [values] - The `values` parameter in the `refill` method is an optional parameter that
|
|
560
|
-
* accepts an iterable of values of type `V` or `undefined`.
|
|
573
|
+
* @param keysNodesEntriesOrRaws - An iterable of items to add.
|
|
574
|
+
* @param [values] - An optional parallel iterable of values.
|
|
561
575
|
*/
|
|
562
576
|
refill(keysNodesEntriesOrRaws, values) {
|
|
563
577
|
this.clear();
|
|
564
578
|
this.addMany(keysNodesEntriesOrRaws, values);
|
|
565
579
|
}
|
|
566
580
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
581
|
+
* Deletes a node from the tree.
|
|
582
|
+
* @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). This implementation finds the node, and if it has two children, swaps it with the rightmost node of its left subtree (in-order predecessor) before deleting. Time O(N) in the worst case. O(N) to find the node (`getNode`) and O(H) (which is O(N) worst-case) to find the rightmost node. Space O(1) (if `getNode` is iterative, which it is).
|
|
569
583
|
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry
|
|
573
|
-
* - The `delete` method you provided is used to delete a node from a binary tree based on the key,
|
|
574
|
-
* node, entry or raw data. The method returns an array of
|
|
575
|
-
* `BinaryTreeDeleteResult` objects containing information about the deleted node and whether
|
|
576
|
-
* balancing is needed.
|
|
577
|
-
* @returns The `delete` method returns an array of `BinaryTreeDeleteResult` objects. Each object in
|
|
578
|
-
* the array contains information about the node that was deleted (`deleted`) and the node that may
|
|
579
|
-
* need to be balanced (`needBalanced`).
|
|
584
|
+
* @param keyNodeOrEntry - The node to delete.
|
|
585
|
+
* @returns An array containing deletion results (for compatibility with self-balancing trees).
|
|
580
586
|
*/
|
|
581
587
|
delete(keyNodeOrEntry) {
|
|
582
588
|
const deletedResult = [];
|
|
@@ -589,14 +595,20 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
589
595
|
let needBalanced;
|
|
590
596
|
let orgCurrent = curr;
|
|
591
597
|
if (!curr.left && !curr.right && !parent) {
|
|
598
|
+
// Deleting the root with no children
|
|
592
599
|
this._setRoot(undefined);
|
|
593
600
|
}
|
|
594
601
|
else if (curr.left) {
|
|
602
|
+
// Node has a left child (or two children)
|
|
603
|
+
// Find the rightmost node in the left subtree
|
|
595
604
|
const leftSubTreeRightMost = this.getRightMost(node => node, curr.left);
|
|
596
605
|
if (leftSubTreeRightMost) {
|
|
597
606
|
const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
|
|
607
|
+
// Swap properties
|
|
598
608
|
orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
|
|
609
|
+
// `orgCurrent` is now the node to be physically deleted (which was the rightmost)
|
|
599
610
|
if (parentOfLeftSubTreeMax) {
|
|
611
|
+
// Unlink the rightmost node
|
|
600
612
|
if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
|
|
601
613
|
parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
|
|
602
614
|
else
|
|
@@ -606,6 +618,8 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
606
618
|
}
|
|
607
619
|
}
|
|
608
620
|
else if (parent) {
|
|
621
|
+
// Node has no left child, but has a parent
|
|
622
|
+
// Promote the right child (which could be null)
|
|
609
623
|
const { familyPosition: fp } = curr;
|
|
610
624
|
if (fp === 'LEFT' || fp === 'ROOT_LEFT') {
|
|
611
625
|
parent.left = curr.right;
|
|
@@ -616,6 +630,8 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
616
630
|
needBalanced = parent;
|
|
617
631
|
}
|
|
618
632
|
else {
|
|
633
|
+
// Deleting the root, which has no left child
|
|
634
|
+
// Promote the right child as the new root
|
|
619
635
|
this._setRoot(curr.right);
|
|
620
636
|
curr.right = undefined;
|
|
621
637
|
}
|
|
@@ -626,28 +642,16 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
626
642
|
return deletedResult;
|
|
627
643
|
}
|
|
628
644
|
/**
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
* @param
|
|
635
|
-
*
|
|
636
|
-
* @param [
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* @param {C} callback - The `callback` parameter in the `search` function is a callback function
|
|
640
|
-
* that will be called on each node that matches the search criteria. It is of type `C`, which
|
|
641
|
-
* extends `NodeCallback<BinaryTreeNode<K, V> | null>`. The default value for `callback` is `this._DEFAULT_NODE_CALLBACK` if
|
|
642
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `search` function is
|
|
643
|
-
* used to specify the node from which the search operation should begin. It represents the starting
|
|
644
|
-
* point in the binary tree where the search will be performed. If no specific `startNode` is
|
|
645
|
-
* provided, the search operation will start from the root
|
|
646
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `search` function
|
|
647
|
-
* specifies the type of iteration to be used when searching for nodes in a binary tree. It can have
|
|
648
|
-
* two possible values:
|
|
649
|
-
* @returns The `search` function returns an array of values that match the provided criteria based
|
|
650
|
-
* on the search algorithm implemented within the function.
|
|
645
|
+
* Searches the tree for nodes matching a predicate.
|
|
646
|
+
* @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). Performs a full DFS (pre-order) scan of the tree. Time O(N), as it may visit every node. Space O(H) for the call stack (recursive) or explicit stack (iterative), where H is the tree height (O(N) worst-case).
|
|
647
|
+
*
|
|
648
|
+
* @template C - The type of the callback function.
|
|
649
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
650
|
+
* @param [onlyOne=false] - If true, stops after finding the first match.
|
|
651
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
|
|
652
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
653
|
+
* @param [iterationType=this.iterationType] - Whether to use 'RECURSIVE' or 'ITERATIVE' search.
|
|
654
|
+
* @returns An array of results from the callback function for each matching node.
|
|
651
655
|
*/
|
|
652
656
|
search(keyNodeEntryOrPredicate, onlyOne = false, callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
|
|
653
657
|
if (keyNodeEntryOrPredicate === undefined)
|
|
@@ -694,74 +698,29 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
694
698
|
}
|
|
695
699
|
return ans;
|
|
696
700
|
}
|
|
697
|
-
/**
|
|
698
|
-
* Time Complexity: O(n)
|
|
699
|
-
* Space Complexity: O(k + log n)
|
|
700
|
-
*
|
|
701
|
-
* The function `getNodes` retrieves nodes from a binary tree based on a key, node, entry, raw data,
|
|
702
|
-
* or predicate, with options for recursive or iterative traversal.
|
|
703
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
|
|
704
|
-
* - The `getNodes` function you provided takes several parameters:
|
|
705
|
-
* @param [onlyOne=false] - The `onlyOne` parameter in the `getNodes` function is a boolean flag that
|
|
706
|
-
* determines whether to return only the first node that matches the criteria specified by the
|
|
707
|
-
* `keyNodeEntryOrPredicate` parameter. If `onlyOne` is set to `true`, the function will
|
|
708
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
709
|
-
* `getNodes` function is used to specify the starting point for traversing the binary tree. It
|
|
710
|
-
* represents the root node of the binary tree or the node from which the traversal should begin. If
|
|
711
|
-
* not provided, the default value is set to `this._root
|
|
712
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNodes` function
|
|
713
|
-
* determines the type of iteration to be performed when traversing the nodes of a binary tree. It
|
|
714
|
-
* can have two possible values:
|
|
715
|
-
* @returns The `getNodes` function returns an array of nodes that satisfy the provided condition
|
|
716
|
-
* based on the input parameters and the iteration type specified.
|
|
717
|
-
*/
|
|
718
701
|
getNodes(keyNodeEntryOrPredicate, onlyOne = false, startNode = this._root, iterationType = this.iterationType) {
|
|
719
702
|
return this.search(keyNodeEntryOrPredicate, onlyOne, node => node, startNode, iterationType);
|
|
720
703
|
}
|
|
721
704
|
/**
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
* @param
|
|
728
|
-
*
|
|
729
|
-
* node, entry, raw data, or a predicate function.
|
|
730
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
731
|
-
* `getNode` function is used to specify the starting point for searching for a node in a binary
|
|
732
|
-
* tree. If no specific starting point is provided, the default value is set to `this._root`, which
|
|
733
|
-
* is typically the root node of the binary tree.
|
|
734
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is
|
|
735
|
-
* used to specify the type of iteration to be performed when searching for a node. It has a default
|
|
736
|
-
* value of `this.iterationType`, which means it will use the iteration type defined in the current
|
|
737
|
-
* context if no specific value is provided
|
|
738
|
-
* @returns The `getNode` function is returning the first node that matches the specified criteria,
|
|
739
|
-
* or `null` if no matching node is found.
|
|
705
|
+
* Gets the first node matching a predicate.
|
|
706
|
+
* @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). Time O(N) in the worst case (via `search`). Space O(H) or O(N) (via `search`).
|
|
707
|
+
*
|
|
708
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
709
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
710
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
711
|
+
* @returns The first matching node, or undefined if not found.
|
|
740
712
|
*/
|
|
741
713
|
getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
|
|
742
714
|
return this.search(keyNodeEntryOrPredicate, true, node => node, startNode, iterationType)[0];
|
|
743
715
|
}
|
|
744
716
|
/**
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
* node
|
|
750
|
-
* @param
|
|
751
|
-
*
|
|
752
|
-
* following types:
|
|
753
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `get`
|
|
754
|
-
* method is used to specify the starting point for searching for a key or node in the binary tree.
|
|
755
|
-
* If no specific starting point is provided, the default starting point is the root of the binary
|
|
756
|
-
* tree (`this._root`).
|
|
757
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `get` method is used
|
|
758
|
-
* to specify the type of iteration to be performed when searching for a key in the binary tree. It
|
|
759
|
-
* is an optional parameter with a default value of `this.iterationType`, which means it will use the
|
|
760
|
-
* iteration type defined in the
|
|
761
|
-
* @returns The `get` method is returning the value associated with the specified key, node, entry,
|
|
762
|
-
* raw data, or predicate in the binary tree map. If the specified key or node is found in the tree,
|
|
763
|
-
* the method returns the corresponding value. If the key or node is not found, it returns
|
|
764
|
-
* `undefined`.
|
|
717
|
+
* Gets the value associated with a key.
|
|
718
|
+
* @remarks Time O(log N), For BST, Red-Black Tree, and AVL Tree subclasses, the worst-case time is O(log N). Time O(1) if in Map mode. O(N) if not in Map mode (uses `getNode`). Space O(1) if in Map mode. O(H) or O(N) otherwise.
|
|
719
|
+
*
|
|
720
|
+
* @param keyNodeEntryOrPredicate - The key, node, or entry to get the value for.
|
|
721
|
+
* @param [startNode=this._root] - The node to start searching from (if not in Map mode).
|
|
722
|
+
* @param [iterationType=this.iterationType] - The traversal method (if not in Map mode).
|
|
723
|
+
* @returns The associated value, or undefined.
|
|
765
724
|
*/
|
|
766
725
|
get(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
|
|
767
726
|
if (this._isMapMode) {
|
|
@@ -772,35 +731,12 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
772
731
|
}
|
|
773
732
|
return this.getNode(keyNodeEntryOrPredicate, startNode, iterationType)?.value;
|
|
774
733
|
}
|
|
775
|
-
/**
|
|
776
|
-
* Time Complexity: O(n)
|
|
777
|
-
* Space Complexity: O(log n)
|
|
778
|
-
*
|
|
779
|
-
* The `has` function in TypeScript checks if a specified key, node, entry, raw data, or predicate
|
|
780
|
-
* exists in the data structure.
|
|
781
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
|
|
782
|
-
* - The `keyNodeEntryOrPredicate` parameter in the `override has` method can accept one of
|
|
783
|
-
* the following types:
|
|
784
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
785
|
-
* `override` method is used to specify the starting point for the search operation within the data
|
|
786
|
-
* structure. It defaults to `this._root` if not provided explicitly.
|
|
787
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `override has` method
|
|
788
|
-
* is used to specify the type of iteration to be performed. It has a default value of
|
|
789
|
-
* `this.iterationType`, which means it will use the iteration type defined in the current context if
|
|
790
|
-
* no value is provided when calling the method.
|
|
791
|
-
* @returns The `override has` method is returning a boolean value. It checks if there are any nodes
|
|
792
|
-
* that match the provided key, node, entry, raw data, or predicate in the tree structure. If there
|
|
793
|
-
* are matching nodes, it returns `true`, indicating that the tree contains the specified element.
|
|
794
|
-
* Otherwise, it returns `false`.
|
|
795
|
-
*/
|
|
796
734
|
has(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
|
|
797
735
|
return this.search(keyNodeEntryOrPredicate, true, node => node, startNode, iterationType).length > 0;
|
|
798
736
|
}
|
|
799
737
|
/**
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* The clear function removes nodes and values in map mode.
|
|
738
|
+
* Clears the tree of all nodes and values.
|
|
739
|
+
* @remarks Time O(N) if in Map mode (due to `_store.clear()`), O(1) otherwise. Space O(1)
|
|
804
740
|
*/
|
|
805
741
|
clear() {
|
|
806
742
|
this._clearNodes();
|
|
@@ -808,55 +744,33 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
808
744
|
this._clearValues();
|
|
809
745
|
}
|
|
810
746
|
/**
|
|
811
|
-
*
|
|
812
|
-
*
|
|
747
|
+
* Checks if the tree is empty.
|
|
748
|
+
* @remarks Time O(1), Space O(1)
|
|
813
749
|
*
|
|
814
|
-
*
|
|
815
|
-
* boolean value.
|
|
816
|
-
* @returns The `isEmpty()` method is returning a boolean value, specifically `true` if the `_size`
|
|
817
|
-
* property is equal to 0, indicating that the data structure is empty, and `false` otherwise.
|
|
750
|
+
* @returns True if the tree has no nodes, false otherwise.
|
|
818
751
|
*/
|
|
819
752
|
isEmpty() {
|
|
820
753
|
return this._size === 0;
|
|
821
754
|
}
|
|
822
755
|
/**
|
|
823
|
-
*
|
|
824
|
-
* Space
|
|
756
|
+
* Checks if the tree is perfectly balanced.
|
|
757
|
+
* @remarks A tree is perfectly balanced if the difference between min and max height is at most 1. Time O(N), as it requires two full traversals (`getMinHeight` and `getHeight`). Space O(H) or O(N) (from height calculation).
|
|
825
758
|
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
|
829
|
-
* point for checking if the binary tree is perfectly balanced. It represents the root node of the
|
|
830
|
-
* binary tree or a specific node from which the balance check should begin.
|
|
831
|
-
* @returns The method `isPerfectlyBalanced` is returning a boolean value, which indicates whether
|
|
832
|
-
* the tree starting from the `startNode` node is perfectly balanced or not. The return value is
|
|
833
|
-
* determined by comparing the minimum height of the tree with the height of the tree. If the minimum
|
|
834
|
-
* height plus 1 is greater than or equal to the height of the tree, then it is considered perfectly
|
|
835
|
-
* balanced and
|
|
759
|
+
* @param [startNode=this._root] - The node to start checking from.
|
|
760
|
+
* @returns True if perfectly balanced, false otherwise.
|
|
836
761
|
*/
|
|
837
762
|
isPerfectlyBalanced(startNode = this._root) {
|
|
838
763
|
return this.getMinHeight(startNode) + 1 >= this.getHeight(startNode);
|
|
839
764
|
}
|
|
840
765
|
/**
|
|
841
|
-
*
|
|
842
|
-
* Space
|
|
766
|
+
* Checks if the tree is a valid Binary Search Tree (BST).
|
|
767
|
+
* @remarks Time O(N), as it must visit every node. Space O(H) for the call stack (recursive) or explicit stack (iterative), where H is the tree height (O(N) worst-case).
|
|
843
768
|
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* @
|
|
847
|
-
* function represents the starting point for checking whether a binary search tree (BST) is valid.
|
|
848
|
-
* It can be a node in the BST or a reference to the root of the BST. If no specific node is
|
|
849
|
-
* provided, the function will default to
|
|
850
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `isBST` function
|
|
851
|
-
* determines whether the function should use a recursive approach or an iterative approach to check
|
|
852
|
-
* if the binary search tree (BST) is valid.
|
|
853
|
-
* @returns The `isBST` method is returning a boolean value, which indicates whether the binary
|
|
854
|
-
* search tree (BST) represented by the given root node is a valid BST or not. The method checks if
|
|
855
|
-
* the tree satisfies the BST property, where for every node, all nodes in its left subtree have keys
|
|
856
|
-
* less than the node's key, and all nodes in its right subtree have keys greater than the node's
|
|
769
|
+
* @param [startNode=this._root] - The node to start checking from.
|
|
770
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
771
|
+
* @returns True if it's a valid BST, false otherwise.
|
|
857
772
|
*/
|
|
858
773
|
isBST(startNode = this._root, iterationType = this.iterationType) {
|
|
859
|
-
// TODO there is a bug
|
|
860
774
|
startNode = this.ensureNode(startNode);
|
|
861
775
|
if (!startNode)
|
|
862
776
|
return true;
|
|
@@ -870,14 +784,14 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
870
784
|
return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
|
|
871
785
|
};
|
|
872
786
|
const isStandardBST = dfs(startNode, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
|
|
873
|
-
const isInverseBST = dfs(startNode, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
|
787
|
+
const isInverseBST = dfs(startNode, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER); // Check for reverse BST
|
|
874
788
|
return isStandardBST || isInverseBST;
|
|
875
789
|
}
|
|
876
790
|
else {
|
|
791
|
+
// Iterative in-order traversal check
|
|
877
792
|
const checkBST = (checkMax = false) => {
|
|
878
793
|
const stack = [];
|
|
879
794
|
let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
|
|
880
|
-
// @ts-ignore
|
|
881
795
|
let curr = startNode;
|
|
882
796
|
while (this.isRealNode(curr) || stack.length > 0) {
|
|
883
797
|
while (this.isRealNode(curr)) {
|
|
@@ -893,25 +807,18 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
893
807
|
}
|
|
894
808
|
return true;
|
|
895
809
|
};
|
|
896
|
-
const isStandardBST = checkBST(false)
|
|
810
|
+
const isStandardBST = checkBST(false);
|
|
811
|
+
const isInverseBST = checkBST(true);
|
|
897
812
|
return isStandardBST || isInverseBST;
|
|
898
813
|
}
|
|
899
814
|
}
|
|
900
815
|
/**
|
|
901
|
-
*
|
|
902
|
-
*
|
|
816
|
+
* Gets the depth of a node (distance from `startNode`).
|
|
817
|
+
* @remarks Time O(H), where H is the depth of the `dist` node relative to `startNode`. O(N) worst-case. Space O(1).
|
|
903
818
|
*
|
|
904
|
-
* The
|
|
905
|
-
* @param
|
|
906
|
-
*
|
|
907
|
-
* It is the target node for which you want to calculate the depth from the `startNode` node.
|
|
908
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
909
|
-
* `getDepth` function represents the starting point from which you want to calculate the depth of a
|
|
910
|
-
* given node or entry in a binary tree. If no specific starting point is provided, the default value
|
|
911
|
-
* for `startNode` is set to the root of the binary
|
|
912
|
-
* @returns The `getDepth` method returns the depth of a given node `dist` relative to the
|
|
913
|
-
* `startNode` node in a binary tree. If the `dist` node is not found in the path to the `startNode`
|
|
914
|
-
* node, it returns the depth of the `dist` node from the root of the tree.
|
|
819
|
+
* @param dist - The node to find the depth of.
|
|
820
|
+
* @param [startNode=this._root] - The node to measure depth from (defaults to root).
|
|
821
|
+
* @returns The depth (0 if `dist` is `startNode`).
|
|
915
822
|
*/
|
|
916
823
|
getDepth(dist, startNode = this._root) {
|
|
917
824
|
let distEnsured = this.ensureNode(dist);
|
|
@@ -927,21 +834,12 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
927
834
|
return depth;
|
|
928
835
|
}
|
|
929
836
|
/**
|
|
930
|
-
*
|
|
931
|
-
* Space
|
|
837
|
+
* Gets the maximum height of the tree (longest path from startNode to a leaf).
|
|
838
|
+
* @remarks Time O(N), as it must visit every node. Space O(H) for recursive stack (O(N) worst-case) or O(N) for iterative stack (storing node + depth).
|
|
932
839
|
*
|
|
933
|
-
*
|
|
934
|
-
*
|
|
935
|
-
* @
|
|
936
|
-
* point from which the height of the binary tree will be calculated. It can be a node in the binary
|
|
937
|
-
* tree or a reference to the root of the tree. If not provided, it defaults to the root of the
|
|
938
|
-
* binary tree data structure.
|
|
939
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is used to determine the type
|
|
940
|
-
* of iteration to be performed while calculating the height of the binary tree. It can have two
|
|
941
|
-
* possible values:
|
|
942
|
-
* @returns The `getHeight` method returns the height of the binary tree starting from the specified
|
|
943
|
-
* root node. The height is calculated based on the maximum depth of the tree, considering either a
|
|
944
|
-
* recursive approach or an iterative approach depending on the `iterationType` parameter.
|
|
840
|
+
* @param [startNode=this._root] - The node to start measuring from.
|
|
841
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
842
|
+
* @returns The height ( -1 for an empty tree, 0 for a single-node tree).
|
|
945
843
|
*/
|
|
946
844
|
getHeight(startNode = this._root, iterationType = this.iterationType) {
|
|
947
845
|
startNode = this.ensureNode(startNode);
|
|
@@ -958,6 +856,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
958
856
|
return _getMaxHeight(startNode);
|
|
959
857
|
}
|
|
960
858
|
else {
|
|
859
|
+
// Iterative (using DFS)
|
|
961
860
|
const stack = [{ node: startNode, depth: 0 }];
|
|
962
861
|
let maxHeight = 0;
|
|
963
862
|
while (stack.length > 0) {
|
|
@@ -972,22 +871,12 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
972
871
|
}
|
|
973
872
|
}
|
|
974
873
|
/**
|
|
975
|
-
*
|
|
976
|
-
* Space
|
|
874
|
+
* Gets the minimum height of the tree (shortest path from startNode to a leaf).
|
|
875
|
+
* @remarks Time O(N), as it must visit every node. Space O(H) for recursive stack (O(N) worst-case) or O(N) for iterative (due to `depths` Map).
|
|
977
876
|
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
980
|
-
* @
|
|
981
|
-
* `getMinHeight` function represents the starting node from which the minimum height of the binary
|
|
982
|
-
* tree will be calculated. It is either a node in the binary tree or a reference to the root of the
|
|
983
|
-
* tree. If not provided, the default value is the root
|
|
984
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getMinHeight` method
|
|
985
|
-
* specifies the type of iteration to use when calculating the minimum height of a binary tree. It
|
|
986
|
-
* can have two possible values:
|
|
987
|
-
* @returns The `getMinHeight` method returns the minimum height of the binary tree starting from the
|
|
988
|
-
* specified root node. The height is calculated based on the shortest path from the root node to a
|
|
989
|
-
* leaf node in the tree. The method uses either a recursive approach or an iterative approach (using
|
|
990
|
-
* a stack) based on the `iterationType` parameter.
|
|
877
|
+
* @param [startNode=this._root] - The node to start measuring from.
|
|
878
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
879
|
+
* @returns The minimum height (-1 for empty, 0 for single node).
|
|
991
880
|
*/
|
|
992
881
|
getMinHeight(startNode = this._root, iterationType = this.iterationType) {
|
|
993
882
|
startNode = this.ensureNode(startNode);
|
|
@@ -998,7 +887,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
998
887
|
if (!this.isRealNode(cur))
|
|
999
888
|
return 0;
|
|
1000
889
|
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right))
|
|
1001
|
-
return 0;
|
|
890
|
+
return 0; // Leaf node
|
|
1002
891
|
const leftMinHeight = _getMinHeight(cur.left);
|
|
1003
892
|
const rightMinHeight = _getMinHeight(cur.right);
|
|
1004
893
|
return Math.min(leftMinHeight, rightMinHeight) + 1;
|
|
@@ -1006,6 +895,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1006
895
|
return _getMinHeight(startNode);
|
|
1007
896
|
}
|
|
1008
897
|
else {
|
|
898
|
+
// Iterative (using post-order DFS)
|
|
1009
899
|
const stack = [];
|
|
1010
900
|
let node = startNode, last = null;
|
|
1011
901
|
const depths = new Map();
|
|
@@ -1034,24 +924,14 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1034
924
|
}
|
|
1035
925
|
}
|
|
1036
926
|
/**
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
* @param
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
* type `C
|
|
1046
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } beginNode - The `beginNode` parameter in the
|
|
1047
|
-
* `getPathToRoot` function can be either a key, a node, an entry, or any other value of type `R`.
|
|
1048
|
-
* @param [isReverse=true] - The `isReverse` parameter in the `getPathToRoot` function determines
|
|
1049
|
-
* whether the resulting path from the given `beginNode` to the root should be in reverse order or
|
|
1050
|
-
* not. If `isReverse` is set to `true`, the path will be reversed before being returned. If `is
|
|
1051
|
-
* @returns The function `getPathToRoot` returns an array of the return values of the callback
|
|
1052
|
-
* function `callback` applied to each node in the path from the `beginNode` to the root node. The
|
|
1053
|
-
* array is either in reverse order or in the original order based on the value of the `isReverse`
|
|
1054
|
-
* parameter.
|
|
927
|
+
* Gets the path from a given node up to the root.
|
|
928
|
+
* @remarks Time O(H), where H is the depth of the `beginNode`. O(N) worst-case. Space O(H) for the result array.
|
|
929
|
+
*
|
|
930
|
+
* @template C - The type of the callback function.
|
|
931
|
+
* @param beginNode - The node to start the path from.
|
|
932
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on each node in the path.
|
|
933
|
+
* @param [isReverse=false] - If true, returns the path from root-to-node.
|
|
934
|
+
* @returns An array of callback results.
|
|
1055
935
|
*/
|
|
1056
936
|
getPathToRoot(beginNode, callback = this._DEFAULT_NODE_CALLBACK, isReverse = false) {
|
|
1057
937
|
const result = [];
|
|
@@ -1059,40 +939,28 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1059
939
|
if (!beginNodeEnsured)
|
|
1060
940
|
return result;
|
|
1061
941
|
while (beginNodeEnsured.parent) {
|
|
1062
|
-
// Array.push + Array.reverse is more efficient than Array.unshift
|
|
1063
942
|
result.push(callback(beginNodeEnsured));
|
|
1064
943
|
beginNodeEnsured = beginNodeEnsured.parent;
|
|
1065
944
|
}
|
|
1066
|
-
result.push(callback(beginNodeEnsured));
|
|
945
|
+
result.push(callback(beginNodeEnsured)); // Add the root
|
|
1067
946
|
return isReverse ? result.reverse() : result;
|
|
1068
947
|
}
|
|
1069
948
|
/**
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
* @param
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1079
|
-
* `getLeftMost` function represents the starting point for finding the leftmost node in a binary
|
|
1080
|
-
* tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
|
|
1081
|
-
* starting point is provided, the function will default
|
|
1082
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getLeftMost` function
|
|
1083
|
-
* specifies the type of iteration to be used when traversing the binary tree nodes. It can have two
|
|
1084
|
-
* possible values:
|
|
1085
|
-
* @returns The `getLeftMost` function returns the result of the callback function `C` applied to the
|
|
1086
|
-
* leftmost node in the binary tree starting from the `startNode` node. If the `startNode` node is
|
|
1087
|
-
* `NIL`, it returns the result of the callback function applied to `undefined`. If the `startNode`
|
|
1088
|
-
* node is not a real node, it returns the result of the callback
|
|
949
|
+
* Finds the leftmost node in a subtree (the node with the smallest key in a BST).
|
|
950
|
+
* @remarks Time O(H), where H is the height of the left spine. O(N) worst-case. Space O(H) for recursive/trampoline stack.
|
|
951
|
+
*
|
|
952
|
+
* @template C - The type of the callback function.
|
|
953
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on the leftmost node.
|
|
954
|
+
* @param [startNode=this._root] - The subtree root to search from.
|
|
955
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
956
|
+
* @returns The callback result for the leftmost node.
|
|
1089
957
|
*/
|
|
1090
958
|
getLeftMost(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
|
|
1091
959
|
if (this.isNIL(startNode))
|
|
1092
960
|
return callback(undefined);
|
|
1093
961
|
startNode = this.ensureNode(startNode);
|
|
1094
962
|
if (!this.isRealNode(startNode))
|
|
1095
|
-
return callback(
|
|
963
|
+
return callback(undefined);
|
|
1096
964
|
if (iterationType === 'RECURSIVE') {
|
|
1097
965
|
const dfs = (cur) => {
|
|
1098
966
|
const { left } = cur;
|
|
@@ -1103,7 +971,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1103
971
|
return callback(dfs(startNode));
|
|
1104
972
|
}
|
|
1105
973
|
else {
|
|
1106
|
-
//
|
|
974
|
+
// Iterative (trampolined to prevent stack overflow, though 'ITERATIVE' usually means a loop)
|
|
1107
975
|
const dfs = makeTrampoline((cur) => {
|
|
1108
976
|
const { left } = cur;
|
|
1109
977
|
if (!this.isRealNode(left))
|
|
@@ -1114,33 +982,21 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1114
982
|
}
|
|
1115
983
|
}
|
|
1116
984
|
/**
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1122
|
-
* @param
|
|
1123
|
-
*
|
|
1124
|
-
*
|
|
1125
|
-
* as
|
|
1126
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1127
|
-
* `getRightMost` function represents the starting point for finding the rightmost node in a binary
|
|
1128
|
-
* tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
|
|
1129
|
-
* starting point is provided, the function will default
|
|
1130
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getRightMost`
|
|
1131
|
-
* function specifies the type of iteration to be used when traversing the binary tree nodes. It can
|
|
1132
|
-
* have two possible values:
|
|
1133
|
-
* @returns The `getRightMost` function returns the result of the callback function `C`, which is
|
|
1134
|
-
* passed as a parameter to the function. The callback function is called with the rightmost node in
|
|
1135
|
-
* the binary tree structure, determined based on the specified iteration type ('RECURSIVE' or
|
|
1136
|
-
* other).
|
|
985
|
+
* Finds the rightmost node in a subtree (the node with the largest key in a BST).
|
|
986
|
+
* @remarks Time O(H), where H is the height of the right spine. O(N) worst-case. Space O(H) for recursive/trampoline stack.
|
|
987
|
+
*
|
|
988
|
+
* @template C - The type of the callback function.
|
|
989
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on the rightmost node.
|
|
990
|
+
* @param [startNode=this._root] - The subtree root to search from.
|
|
991
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
992
|
+
* @returns The callback result for the rightmost node.
|
|
1137
993
|
*/
|
|
1138
994
|
getRightMost(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
|
|
1139
995
|
if (this.isNIL(startNode))
|
|
1140
996
|
return callback(undefined);
|
|
1141
997
|
startNode = this.ensureNode(startNode);
|
|
1142
998
|
if (!startNode)
|
|
1143
|
-
return callback(
|
|
999
|
+
return callback(undefined);
|
|
1144
1000
|
if (iterationType === 'RECURSIVE') {
|
|
1145
1001
|
const dfs = (cur) => {
|
|
1146
1002
|
const { right } = cur;
|
|
@@ -1151,7 +1007,6 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1151
1007
|
return callback(dfs(startNode));
|
|
1152
1008
|
}
|
|
1153
1009
|
else {
|
|
1154
|
-
// Indirect implementation of iteration using tail recursion optimization
|
|
1155
1010
|
const dfs = makeTrampoline((cur) => {
|
|
1156
1011
|
const { right } = cur;
|
|
1157
1012
|
if (!this.isRealNode(right))
|
|
@@ -1162,17 +1017,11 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1162
1017
|
}
|
|
1163
1018
|
}
|
|
1164
1019
|
/**
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1020
|
+
* Gets the Morris traversal predecessor (rightmost node in the left subtree, or node itself).
|
|
1021
|
+
* @remarks This is primarily a helper for Morris traversal. Time O(H), where H is the height of the left subtree. O(N) worst-case. Space O(1).
|
|
1167
1022
|
*
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
* @param {BinaryTreeNode<K, V>} node - The `getPredecessor` function you provided seems to be attempting to find the
|
|
1171
|
-
* predecessor of a given node in a binary tree. However, there seems to be a logical issue in the
|
|
1172
|
-
* while loop condition that might cause an infinite loop.
|
|
1173
|
-
* @returns The `getPredecessor` function returns the predecessor node of the input `BinaryTreeNode<K, V>` parameter.
|
|
1174
|
-
* If the left child of the input node exists, it traverses to the rightmost node of the left subtree
|
|
1175
|
-
* to find the predecessor. If the left child does not exist, it returns the input node itself.
|
|
1023
|
+
* @param node - The node to find the predecessor for.
|
|
1024
|
+
* @returns The Morris predecessor.
|
|
1176
1025
|
*/
|
|
1177
1026
|
getPredecessor(node) {
|
|
1178
1027
|
if (this.isRealNode(node.left)) {
|
|
@@ -1189,17 +1038,11 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1189
1038
|
}
|
|
1190
1039
|
}
|
|
1191
1040
|
/**
|
|
1192
|
-
*
|
|
1193
|
-
*
|
|
1041
|
+
* Gets the in-order successor of a node in a BST.
|
|
1042
|
+
* @remarks Time O(H), where H is the tree height. O(N) worst-case. Space O(H) (due to `getLeftMost` stack).
|
|
1194
1043
|
*
|
|
1195
|
-
*
|
|
1196
|
-
*
|
|
1197
|
-
* @param {K | BinaryTreeNode<K, V> | null} [x] - The `getSuccessor` function takes a parameter `x`, which can be of
|
|
1198
|
-
* type `K`, `BinaryTreeNode<K, V>`, or `null`.
|
|
1199
|
-
* @returns The `getSuccessor` function returns the successor node of the input node `x`. If `x` has
|
|
1200
|
-
* a right child, the function returns the leftmost node in the right subtree of `x`. If `x` does not
|
|
1201
|
-
* have a right child, the function traverses up the parent nodes until it finds a node that is not
|
|
1202
|
-
* the right child of its parent, and returns that node
|
|
1044
|
+
* @param [x] - The node to find the successor of.
|
|
1045
|
+
* @returns The successor node, or null/undefined if none exists.
|
|
1203
1046
|
*/
|
|
1204
1047
|
getSuccessor(x) {
|
|
1205
1048
|
x = this.ensureNode(x);
|
|
@@ -1216,32 +1059,17 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1216
1059
|
return y;
|
|
1217
1060
|
}
|
|
1218
1061
|
/**
|
|
1219
|
-
*
|
|
1220
|
-
* Space
|
|
1221
|
-
*
|
|
1222
|
-
*
|
|
1223
|
-
*
|
|
1224
|
-
* @param
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
* @param
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1230
|
-
* @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `dfs` function is a boolean flag
|
|
1231
|
-
* that determines whether the depth-first search should stop after finding the first matching node
|
|
1232
|
-
* or continue searching for all matching nodes. If `onlyOne` is set to `true`, the search will stop
|
|
1233
|
-
* after finding the first matching node
|
|
1234
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
|
|
1235
|
-
* startNode - The `startNode` parameter in the `dfs` function can be one of the following types:
|
|
1236
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `dfs` function
|
|
1237
|
-
* specifies the type of iteration to be performed during the Depth-First Search traversal. It is
|
|
1238
|
-
* used to determine the order in which nodes are visited during the traversal. The possible values
|
|
1239
|
-
* for `iterationType` are typically defined as an enum or a
|
|
1240
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `dfs` function determines whether
|
|
1241
|
-
* null nodes should be included in the depth-first search traversal. If `includeNull` is set to
|
|
1242
|
-
* `true`, null nodes will be included in the traversal process. If it is set to `false`, null nodes
|
|
1243
|
-
* will be skipped
|
|
1244
|
-
* @returns The `dfs` method is returning an array of the return type of the callback function `C`.
|
|
1062
|
+
* Performs a Depth-First Search (DFS) traversal.
|
|
1063
|
+
* @remarks Time O(N), visits every node. Space O(H) for the call/explicit stack. O(N) worst-case.
|
|
1064
|
+
*
|
|
1065
|
+
* @template C - The type of the callback function.
|
|
1066
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1067
|
+
* @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
|
|
1068
|
+
* @param [onlyOne=false] - If true, stops after the first callback.
|
|
1069
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1070
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1071
|
+
* @param [includeNull=false] - If true, includes null nodes in the traversal.
|
|
1072
|
+
* @returns An array of callback results.
|
|
1245
1073
|
*/
|
|
1246
1074
|
dfs(callback = this._DEFAULT_NODE_CALLBACK, pattern = 'IN', onlyOne = false, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
|
|
1247
1075
|
startNode = this.ensureNode(startNode);
|
|
@@ -1250,27 +1078,15 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1250
1078
|
return this._dfs(callback, pattern, onlyOne, startNode, iterationType, includeNull);
|
|
1251
1079
|
}
|
|
1252
1080
|
/**
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
*
|
|
1256
|
-
*
|
|
1257
|
-
*
|
|
1258
|
-
* @param
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
* @
|
|
1262
|
-
* function represents the starting point for the breadth-first search traversal in a binary tree. It
|
|
1263
|
-
* can be specified as a key, node, or entry in the binary tree structure. If not provided, the
|
|
1264
|
-
* default value is the root node of the binary
|
|
1265
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `bfs` function
|
|
1266
|
-
* determines the type of iteration to be performed on the binary tree nodes. It can have two
|
|
1267
|
-
* possible values:
|
|
1268
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `bfs` function determines whether
|
|
1269
|
-
* to include `null` values in the breadth-first search traversal of a binary tree. If `includeNull`
|
|
1270
|
-
* is set to `true`, the traversal will include `null` values for nodes that do not have children
|
|
1271
|
-
* (left
|
|
1272
|
-
* @returns The `bfs` function returns an array of values that are the result of applying the
|
|
1273
|
-
* provided callback function to each node in the binary tree in a breadth-first search manner.
|
|
1081
|
+
* Performs a Breadth-First Search (BFS) or Level-Order traversal.
|
|
1082
|
+
* @remarks Time O(N), visits every node. Space O(N) in the worst case for the queue (e.g., a full last level).
|
|
1083
|
+
*
|
|
1084
|
+
* @template C - The type of the callback function.
|
|
1085
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1086
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1087
|
+
* @param [iterationType=this.iterationType] - The traversal method ('RECURSIVE' BFS is less common but supported here).
|
|
1088
|
+
* @param [includeNull=false] - If true, includes null nodes in the traversal.
|
|
1089
|
+
* @returns An array of callback results.
|
|
1274
1090
|
*/
|
|
1275
1091
|
bfs(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
|
|
1276
1092
|
startNode = this.ensureNode(startNode);
|
|
@@ -1278,6 +1094,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1278
1094
|
return [];
|
|
1279
1095
|
const ans = [];
|
|
1280
1096
|
if (iterationType === 'RECURSIVE') {
|
|
1097
|
+
// This is a "recursive" BFS, which is atypical. It uses a queue but calls itself.
|
|
1281
1098
|
const queue = new Queue([
|
|
1282
1099
|
startNode
|
|
1283
1100
|
]);
|
|
@@ -1303,9 +1120,10 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1303
1120
|
dfs(0);
|
|
1304
1121
|
}
|
|
1305
1122
|
else {
|
|
1123
|
+
// Standard iterative BFS
|
|
1306
1124
|
const queue = new Queue([startNode]);
|
|
1307
1125
|
while (queue.length > 0) {
|
|
1308
|
-
const levelSize = queue.length;
|
|
1126
|
+
const levelSize = queue.length; // Not strictly needed here, but good for level-by-level
|
|
1309
1127
|
for (let i = 0; i < levelSize; i++) {
|
|
1310
1128
|
const current = queue.shift();
|
|
1311
1129
|
ans.push(callback(current));
|
|
@@ -1327,22 +1145,14 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1327
1145
|
return ans;
|
|
1328
1146
|
}
|
|
1329
1147
|
/**
|
|
1330
|
-
*
|
|
1331
|
-
* Space
|
|
1148
|
+
* Finds all leaf nodes in the tree.
|
|
1149
|
+
* @remarks Time O(N), visits every node. Space O(H) for recursive stack or O(N) for iterative queue.
|
|
1332
1150
|
*
|
|
1333
|
-
*
|
|
1334
|
-
*
|
|
1335
|
-
* @param
|
|
1336
|
-
*
|
|
1337
|
-
* @
|
|
1338
|
-
* method is used to specify the starting point for finding and processing the leaves of a binary
|
|
1339
|
-
* tree. It can be provided as either a key, a node, or an entry in the binary tree structure. If not
|
|
1340
|
-
* explicitly provided, the default value
|
|
1341
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `leaves` method
|
|
1342
|
-
* specifies the type of iteration to be performed when collecting the leaves of a binary tree. It
|
|
1343
|
-
* can have two possible values:
|
|
1344
|
-
* @returns The `leaves` method returns an array of values that are the result of applying the
|
|
1345
|
-
* provided callback function to each leaf node in the binary tree.
|
|
1151
|
+
* @template C - The type of the callback function.
|
|
1152
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
|
|
1153
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1154
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1155
|
+
* @returns An array of callback results.
|
|
1346
1156
|
*/
|
|
1347
1157
|
leaves(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
|
|
1348
1158
|
startNode = this.ensureNode(startNode);
|
|
@@ -1350,6 +1160,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1350
1160
|
if (!this.isRealNode(startNode))
|
|
1351
1161
|
return [];
|
|
1352
1162
|
if (iterationType === 'RECURSIVE') {
|
|
1163
|
+
// DFS-based
|
|
1353
1164
|
const dfs = (cur) => {
|
|
1354
1165
|
if (this.isLeaf(cur)) {
|
|
1355
1166
|
leaves.push(callback(cur));
|
|
@@ -1364,6 +1175,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1364
1175
|
dfs(startNode);
|
|
1365
1176
|
}
|
|
1366
1177
|
else {
|
|
1178
|
+
// BFS-based
|
|
1367
1179
|
const queue = new Queue([startNode]);
|
|
1368
1180
|
while (queue.length > 0) {
|
|
1369
1181
|
const cur = queue.shift();
|
|
@@ -1381,28 +1193,15 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1381
1193
|
return leaves;
|
|
1382
1194
|
}
|
|
1383
1195
|
/**
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
* @param
|
|
1390
|
-
*
|
|
1391
|
-
*
|
|
1392
|
-
* @
|
|
1393
|
-
* `listLevels` function represents the starting point for traversing the binary tree. It can be
|
|
1394
|
-
* either a key, a node, or an entry in the binary tree. If not provided, the default value is the
|
|
1395
|
-
* root of the binary tree.
|
|
1396
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `listLevels` function
|
|
1397
|
-
* determines the type of iteration to be performed on the binary tree nodes. It can have two
|
|
1398
|
-
* possible values:
|
|
1399
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `listLevels` method determines
|
|
1400
|
-
* whether or not to include null nodes in the traversal of the binary tree. If `includeNull` is set
|
|
1401
|
-
* to `true`, the traversal will include null nodes in the levels of the tree. If set to `false`,
|
|
1402
|
-
* null
|
|
1403
|
-
* @returns The `listLevels` method returns an array of arrays, where each inner array represents a
|
|
1404
|
-
* level in a binary tree. Each inner array contains the return value of the provided callback
|
|
1405
|
-
* function applied to the nodes at that level.
|
|
1196
|
+
* Returns a 2D array of nodes, grouped by level.
|
|
1197
|
+
* @remarks Time O(N), visits every node. Space O(N) for the result array and the queue/stack.
|
|
1198
|
+
*
|
|
1199
|
+
* @template C - The type of the callback function.
|
|
1200
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1201
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1202
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1203
|
+
* @param [includeNull=false] - If true, includes null nodes.
|
|
1204
|
+
* @returns A 2D array of callback results.
|
|
1406
1205
|
*/
|
|
1407
1206
|
listLevels(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
|
|
1408
1207
|
startNode = this.ensureNode(startNode);
|
|
@@ -1410,6 +1209,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1410
1209
|
if (!startNode)
|
|
1411
1210
|
return levelsNodes;
|
|
1412
1211
|
if (iterationType === 'RECURSIVE') {
|
|
1212
|
+
// Pre-order DFS based level listing
|
|
1413
1213
|
const _recursive = (node, level) => {
|
|
1414
1214
|
if (!levelsNodes[level])
|
|
1415
1215
|
levelsNodes[level] = [];
|
|
@@ -1430,6 +1230,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1430
1230
|
_recursive(startNode, 0);
|
|
1431
1231
|
}
|
|
1432
1232
|
else {
|
|
1233
|
+
// Iterative DFS based level listing
|
|
1433
1234
|
const stack = [[startNode, 0]];
|
|
1434
1235
|
while (stack.length > 0) {
|
|
1435
1236
|
const head = stack.pop();
|
|
@@ -1454,24 +1255,14 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1454
1255
|
return levelsNodes;
|
|
1455
1256
|
}
|
|
1456
1257
|
/**
|
|
1457
|
-
*
|
|
1458
|
-
*
|
|
1459
|
-
*
|
|
1460
|
-
*
|
|
1461
|
-
*
|
|
1462
|
-
* @param
|
|
1463
|
-
*
|
|
1464
|
-
*
|
|
1465
|
-
* @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `morris` function specifies
|
|
1466
|
-
* the type of Depth-First Search (DFS) order pattern to traverse the binary tree. The possible
|
|
1467
|
-
* values for the `pattern` parameter are:
|
|
1468
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `morris`
|
|
1469
|
-
* function is the starting point for the Morris traversal algorithm. It represents the root node of
|
|
1470
|
-
* the binary tree or the node from which the traversal should begin. It can be provided as either a
|
|
1471
|
-
* key, a node, an entry, or a reference
|
|
1472
|
-
* @returns The `morris` function is returning an array of values that are the result of applying the
|
|
1473
|
-
* provided callback function to each node in the binary tree in the specified order pattern (IN,
|
|
1474
|
-
* PRE, or POST).
|
|
1258
|
+
* Performs a Morris (threaded) traversal.
|
|
1259
|
+
* @remarks This traversal uses O(1) extra space (excluding the result array) by temporarily modifying the tree's right child pointers. Time O(N), as each node is visited a constant number of times. Space O(1) (excluding the `ans` array).
|
|
1260
|
+
*
|
|
1261
|
+
* @template C - The type of the callback function.
|
|
1262
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1263
|
+
* @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
|
|
1264
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1265
|
+
* @returns An array of callback results.
|
|
1475
1266
|
*/
|
|
1476
1267
|
morris(callback = this._DEFAULT_NODE_CALLBACK, pattern = 'IN', startNode = this._root) {
|
|
1477
1268
|
startNode = this.ensureNode(startNode);
|
|
@@ -1479,6 +1270,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1479
1270
|
return [];
|
|
1480
1271
|
const ans = [];
|
|
1481
1272
|
let cur = startNode;
|
|
1273
|
+
// Helper to reverse a linked list (formed by right pointers)
|
|
1482
1274
|
const _reverseEdge = (node) => {
|
|
1483
1275
|
let pre = null;
|
|
1484
1276
|
let next = null;
|
|
@@ -1490,6 +1282,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1490
1282
|
}
|
|
1491
1283
|
return pre;
|
|
1492
1284
|
};
|
|
1285
|
+
// Helper to print the reversed edge (for post-order)
|
|
1493
1286
|
const _printEdge = (node) => {
|
|
1494
1287
|
const tail = _reverseEdge(node);
|
|
1495
1288
|
let cur = tail;
|
|
@@ -1497,7 +1290,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1497
1290
|
ans.push(callback(cur));
|
|
1498
1291
|
cur = cur.right;
|
|
1499
1292
|
}
|
|
1500
|
-
_reverseEdge(tail);
|
|
1293
|
+
_reverseEdge(tail); // Restore the edge
|
|
1501
1294
|
};
|
|
1502
1295
|
switch (pattern) {
|
|
1503
1296
|
case 'IN':
|
|
@@ -1505,11 +1298,13 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1505
1298
|
if (cur.left) {
|
|
1506
1299
|
const predecessor = this.getPredecessor(cur);
|
|
1507
1300
|
if (!predecessor.right) {
|
|
1301
|
+
// Create thread
|
|
1508
1302
|
predecessor.right = cur;
|
|
1509
1303
|
cur = cur.left;
|
|
1510
1304
|
continue;
|
|
1511
1305
|
}
|
|
1512
1306
|
else {
|
|
1307
|
+
// Remove thread
|
|
1513
1308
|
predecessor.right = null;
|
|
1514
1309
|
}
|
|
1515
1310
|
}
|
|
@@ -1522,12 +1317,14 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1522
1317
|
if (cur.left) {
|
|
1523
1318
|
const predecessor = this.getPredecessor(cur);
|
|
1524
1319
|
if (!predecessor.right) {
|
|
1320
|
+
// Create thread and visit
|
|
1525
1321
|
predecessor.right = cur;
|
|
1526
1322
|
ans.push(callback(cur));
|
|
1527
1323
|
cur = cur.left;
|
|
1528
1324
|
continue;
|
|
1529
1325
|
}
|
|
1530
1326
|
else {
|
|
1327
|
+
// Remove thread
|
|
1531
1328
|
predecessor.right = null;
|
|
1532
1329
|
}
|
|
1533
1330
|
}
|
|
@@ -1542,108 +1339,77 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1542
1339
|
if (cur.left) {
|
|
1543
1340
|
const predecessor = this.getPredecessor(cur);
|
|
1544
1341
|
if (predecessor.right === null) {
|
|
1342
|
+
// Create thread
|
|
1545
1343
|
predecessor.right = cur;
|
|
1546
1344
|
cur = cur.left;
|
|
1547
1345
|
continue;
|
|
1548
1346
|
}
|
|
1549
1347
|
else {
|
|
1348
|
+
// Remove thread and print right spine of left child
|
|
1550
1349
|
predecessor.right = null;
|
|
1551
1350
|
_printEdge(cur.left);
|
|
1552
1351
|
}
|
|
1553
1352
|
}
|
|
1554
1353
|
cur = cur.right;
|
|
1555
1354
|
}
|
|
1556
|
-
_printEdge(startNode);
|
|
1355
|
+
_printEdge(startNode); // Print the right spine of the root
|
|
1557
1356
|
break;
|
|
1558
1357
|
}
|
|
1559
1358
|
return ans;
|
|
1560
1359
|
}
|
|
1561
1360
|
/**
|
|
1562
|
-
*
|
|
1563
|
-
*
|
|
1361
|
+
* Clones the tree.
|
|
1362
|
+
* @remarks Time O(N * M), where N is the number of nodes and M is the tree size during insertion (due to `bfs` + `add`, and `add` is O(M)). Space O(N) for the new tree and the BFS queue.
|
|
1564
1363
|
*
|
|
1565
|
-
*
|
|
1566
|
-
* search.
|
|
1567
|
-
* @returns The `clone()` method is returning a cloned copy of the tree with the same structure and
|
|
1568
|
-
* values as the original tree. The method creates a new tree, iterates over the nodes of the
|
|
1569
|
-
* original tree using breadth-first search (bfs), and adds the nodes to the new tree. If a node in
|
|
1570
|
-
* the original tree is null, a null node is added to the cloned tree. If a node
|
|
1364
|
+
* @returns A new, cloned instance of the tree.
|
|
1571
1365
|
*/
|
|
1572
1366
|
clone() {
|
|
1573
|
-
const
|
|
1574
|
-
this._clone(
|
|
1575
|
-
return
|
|
1576
|
-
}
|
|
1577
|
-
/**
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
* @
|
|
1584
|
-
* called with four arguments: the `value` of the current entry, the `key` of the current entry, the
|
|
1585
|
-
* `index` of the current entry in the iteration, and the reference to the tree itself (`
|
|
1586
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `filter` method allows you to specify the
|
|
1587
|
-
* value of `this` that should be used when executing the `predicate` function. This is useful when
|
|
1588
|
-
* the `predicate` function relies on the context of a specific object or value. By providing a
|
|
1589
|
-
* `thisArg
|
|
1590
|
-
* @returns The `filter` method is returning a new tree that contains entries that pass the provided
|
|
1591
|
-
* predicate function.
|
|
1367
|
+
const out = this._createInstance();
|
|
1368
|
+
this._clone(out);
|
|
1369
|
+
return out;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Creates a new tree containing only the entries that satisfy the predicate.
|
|
1373
|
+
* @remarks Time O(N * M), where N is nodes in this tree, and M is size of the new tree during insertion (O(N) iteration + O(M) `add` for each item). Space O(N) for the new tree.
|
|
1374
|
+
*
|
|
1375
|
+
* @param predicate - A function to test each [key, value] pair.
|
|
1376
|
+
* @param [thisArg] - `this` context for the predicate.
|
|
1377
|
+
* @returns A new, filtered tree.
|
|
1592
1378
|
*/
|
|
1593
1379
|
filter(predicate, thisArg) {
|
|
1594
|
-
const
|
|
1595
|
-
let
|
|
1596
|
-
for (const [
|
|
1597
|
-
if (predicate.call(thisArg,
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
*
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1608
|
-
*
|
|
1609
|
-
* @param
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
}
|
|
1628
|
-
return newTree;
|
|
1629
|
-
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Time Complexity: O(n)
|
|
1632
|
-
* Space Complexity: O(n)
|
|
1633
|
-
*
|
|
1634
|
-
* The function `toVisual` in TypeScript overrides the visual representation of a binary tree with
|
|
1635
|
-
* customizable options for displaying undefined, null, and sentinel nodes.
|
|
1636
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1637
|
-
* `toVisual` method is used to specify the starting point for visualizing the binary tree structure.
|
|
1638
|
-
* It can be a node, key, entry, or the root of the tree. If no specific starting point is provided,
|
|
1639
|
-
* the default is set to the root
|
|
1640
|
-
* @param {BinaryTreePrintOptions} [options] - The `options` parameter in the `toVisual` method is an
|
|
1641
|
-
* object that contains the following properties:
|
|
1642
|
-
* @returns The `override toVisual` method returns a string that represents the visual display of the
|
|
1643
|
-
* binary tree based on the provided options for showing undefined, null, and Red-Black NIL nodes.
|
|
1644
|
-
* The method constructs the visual representation by calling the `_displayAux` method and appending
|
|
1645
|
-
* the lines to the output string. The final output string contains the visual representation of the
|
|
1646
|
-
* binary tree with the specified options.
|
|
1380
|
+
const out = this._createInstance();
|
|
1381
|
+
let i = 0;
|
|
1382
|
+
for (const [k, v] of this)
|
|
1383
|
+
if (predicate.call(thisArg, k, v, i++, this))
|
|
1384
|
+
out.add([k, v]);
|
|
1385
|
+
return out;
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Creates a new tree by mapping each [key, value] pair to a new entry.
|
|
1389
|
+
* @remarks Time O(N * M), where N is nodes in this tree, and M is size of the new tree during insertion. Space O(N) for the new tree.
|
|
1390
|
+
*
|
|
1391
|
+
* @template MK - New key type.
|
|
1392
|
+
* @template MV - New value type.
|
|
1393
|
+
* @template MR - New raw type.
|
|
1394
|
+
* @param cb - A function to map each [key, value] pair.
|
|
1395
|
+
* @param [options] - Options for the new tree.
|
|
1396
|
+
* @param [thisArg] - `this` context for the callback.
|
|
1397
|
+
* @returns A new, mapped tree.
|
|
1398
|
+
*/
|
|
1399
|
+
map(cb, options, thisArg) {
|
|
1400
|
+
const out = this._createLike([], options);
|
|
1401
|
+
let i = 0;
|
|
1402
|
+
for (const [k, v] of this)
|
|
1403
|
+
out.add(cb.call(thisArg, k, v, i++, this));
|
|
1404
|
+
return out;
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Generates a string representation of the tree for visualization.
|
|
1408
|
+
* @remarks Time O(N), visits every node. Space O(N*H) or O(N^2) in the worst case, as the string width can grow significantly.
|
|
1409
|
+
*
|
|
1410
|
+
* @param [startNode=this._root] - The node to start printing from.
|
|
1411
|
+
* @param [options] - Options to control the output (e.g., show nulls).
|
|
1412
|
+
* @returns The string representation of the tree.
|
|
1647
1413
|
*/
|
|
1648
1414
|
toVisual(startNode = this._root, options) {
|
|
1649
1415
|
const opts = { isShowUndefined: false, isShowNull: true, isShowRedBlackNIL: false, ...options };
|
|
@@ -1669,117 +1435,31 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1669
1435
|
return output;
|
|
1670
1436
|
}
|
|
1671
1437
|
/**
|
|
1672
|
-
*
|
|
1673
|
-
* Space
|
|
1438
|
+
* Prints a visual representation of the tree to the console.
|
|
1439
|
+
* @remarks Time O(N) (via `toVisual`). Space O(N*H) or O(N^2) (via `toVisual`).
|
|
1674
1440
|
*
|
|
1675
|
-
*
|
|
1676
|
-
*
|
|
1677
|
-
* @param {BinaryTreePrintOptions} [options] - The `options` parameter is used to specify the
|
|
1678
|
-
* printing options for the binary tree. It is an optional parameter that allows you to customize how
|
|
1679
|
-
* the binary tree is printed, such as choosing between different traversal orders or formatting
|
|
1680
|
-
* options.
|
|
1681
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1682
|
-
* `override print` method is used to specify the starting point for printing the binary tree. It can
|
|
1683
|
-
* be either a key, a node, an entry, or the root of the tree. If no specific starting point is
|
|
1684
|
-
* provided, the default value is set to
|
|
1441
|
+
* @param [options] - Options to control the output.
|
|
1442
|
+
* @param [startNode=this._root] - The node to start printing from.
|
|
1685
1443
|
*/
|
|
1686
1444
|
print(options, startNode = this._root) {
|
|
1687
1445
|
console.log(this.toVisual(startNode, options));
|
|
1688
1446
|
}
|
|
1689
|
-
_clone(cloned) {
|
|
1690
|
-
this.bfs(node => {
|
|
1691
|
-
if (node === null)
|
|
1692
|
-
cloned.add(null);
|
|
1693
|
-
else {
|
|
1694
|
-
if (this._isMapMode)
|
|
1695
|
-
cloned.add([node.key, this._store.get(node.key)]);
|
|
1696
|
-
else
|
|
1697
|
-
cloned.add([node.key, node.value]);
|
|
1698
|
-
}
|
|
1699
|
-
}, this._root, this.iterationType, true);
|
|
1700
|
-
if (this._isMapMode)
|
|
1701
|
-
cloned._store = this._store;
|
|
1702
|
-
}
|
|
1703
1447
|
/**
|
|
1704
|
-
*
|
|
1705
|
-
* Space
|
|
1448
|
+
* (Protected) Core DFS implementation.
|
|
1449
|
+
* @remarks Time O(N), visits every node satisfying predicates. Space O(H) for call/explicit stack. O(N) worst-case.
|
|
1706
1450
|
*
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1709
|
-
* @param
|
|
1710
|
-
*
|
|
1711
|
-
*
|
|
1712
|
-
*
|
|
1713
|
-
* @param
|
|
1714
|
-
*
|
|
1715
|
-
*
|
|
1716
|
-
* @
|
|
1717
|
-
*
|
|
1718
|
-
*
|
|
1719
|
-
* value.
|
|
1720
|
-
*/
|
|
1721
|
-
_keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value) {
|
|
1722
|
-
if (keyNodeOrEntry === undefined)
|
|
1723
|
-
return [undefined, undefined];
|
|
1724
|
-
if (keyNodeOrEntry === null)
|
|
1725
|
-
return [null, undefined];
|
|
1726
|
-
if (this.isNode(keyNodeOrEntry))
|
|
1727
|
-
return [keyNodeOrEntry, value];
|
|
1728
|
-
if (this.isEntry(keyNodeOrEntry)) {
|
|
1729
|
-
const [key, entryValue] = keyNodeOrEntry;
|
|
1730
|
-
if (key === undefined)
|
|
1731
|
-
return [undefined, undefined];
|
|
1732
|
-
else if (key === null)
|
|
1733
|
-
return [null, undefined];
|
|
1734
|
-
const finalValue = value ?? entryValue;
|
|
1735
|
-
return [this.createNode(key, finalValue), finalValue];
|
|
1736
|
-
}
|
|
1737
|
-
return [this.createNode(keyNodeOrEntry, value), value];
|
|
1738
|
-
}
|
|
1739
|
-
/**
|
|
1740
|
-
* Time complexity: O(n)
|
|
1741
|
-
* Space complexity: O(n)
|
|
1742
|
-
*
|
|
1743
|
-
* The `_dfs` function performs a depth-first search traversal on a binary tree, with customizable
|
|
1744
|
-
* options for traversal order and node processing.
|
|
1745
|
-
* @param {C} callback - The `callback` parameter in the `_dfs` method is a function that will be
|
|
1746
|
-
* called on each node visited during the depth-first search traversal. It is a generic type `C` that
|
|
1747
|
-
* extends `NodeCallback<BinaryTreeNode<K, V> | null>`. The default value for `callback`
|
|
1748
|
-
* @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `_dfs` method specifies the
|
|
1749
|
-
* order in which the nodes are visited during a depth-first search traversal. It can have one of the
|
|
1750
|
-
* following values:
|
|
1751
|
-
* @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `_dfs` method is a boolean flag
|
|
1752
|
-
* that determines whether the traversal should stop after processing a single node. If `onlyOne` is
|
|
1753
|
-
* set to `true`, the traversal will return as soon as a single node is processed. If it is set to
|
|
1754
|
-
* `false
|
|
1755
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
|
|
1756
|
-
* startNode - The `startNode` parameter in the `_dfs` method is used to specify the starting node
|
|
1757
|
-
* for the depth-first search traversal. It can be provided in different forms:
|
|
1758
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `_dfs` method
|
|
1759
|
-
* specifies whether the traversal should be done recursively or iteratively. It can have two
|
|
1760
|
-
* possible values:
|
|
1761
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `_dfs` method determines whether
|
|
1762
|
-
* null nodes should be included in the traversal process. If `includeNull` is set to `true`, the
|
|
1763
|
-
* method will consider null nodes as valid nodes to visit or process. If `includeNull` is set to
|
|
1764
|
-
* `false`,
|
|
1765
|
-
* @param shouldVisitLeft - The `shouldVisitLeft` parameter in the `_dfs` method is a function that
|
|
1766
|
-
* determines whether the left child of a node should be visited during the Depth-First Search
|
|
1767
|
-
* traversal. By default, it checks if the node is not null or undefined before visiting the left
|
|
1768
|
-
* child. You can customize this behavior
|
|
1769
|
-
* @param shouldVisitRight - The `shouldVisitRight` parameter in the `_dfs` method is a function that
|
|
1770
|
-
* determines whether to visit the right child node of the current node during a depth-first search
|
|
1771
|
-
* traversal. The default implementation of this function checks if the node is not null or undefined
|
|
1772
|
-
* before deciding to visit it.
|
|
1773
|
-
* @param shouldVisitRoot - The `shouldVisitRoot` parameter in the `_dfs` method is a function that
|
|
1774
|
-
* determines whether a given node should be visited during the depth-first search traversal. The
|
|
1775
|
-
* function takes a node as an argument and returns a boolean value indicating whether the node
|
|
1776
|
-
* should be visited.
|
|
1777
|
-
* @param shouldProcessRoot - The `shouldProcessRoot` parameter in the `_dfs` method is a function
|
|
1778
|
-
* that determines whether the root node should be processed during the Depth-First Search traversal.
|
|
1779
|
-
* It takes a node (BinaryTreeNode<K, V> | null | undefined) as input and returns a boolean value. If
|
|
1780
|
-
* the function
|
|
1781
|
-
* @returns The `_dfs` method returns an array of the return type of the provided callback function
|
|
1782
|
-
* `C`.
|
|
1451
|
+
* @template C - Callback type.
|
|
1452
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on nodes.
|
|
1453
|
+
* @param [pattern='IN'] - Traversal order.
|
|
1454
|
+
* @param [onlyOne=false] - Stop after first match.
|
|
1455
|
+
* @param [startNode=this._root] - Starting node.
|
|
1456
|
+
* @param [iterationType=this.iterationType] - Traversal method.
|
|
1457
|
+
* @param [includeNull=false] - Include nulls.
|
|
1458
|
+
* @param [shouldVisitLeft] - Predicate to traverse left.
|
|
1459
|
+
* @param [shouldVisitRight] - Predicate to traverse right.
|
|
1460
|
+
* @param [shouldVisitRoot] - Predicate to visit root.
|
|
1461
|
+
* @param [shouldProcessRoot] - Predicate to process root.
|
|
1462
|
+
* @returns Array of callback results.
|
|
1783
1463
|
*/
|
|
1784
1464
|
_dfs(callback = this._DEFAULT_NODE_CALLBACK, pattern = 'IN', onlyOne = false, startNode = this._root, iterationType = this.iterationType, includeNull = false, shouldVisitLeft = node => !!node, shouldVisitRight = node => !!node, shouldVisitRoot = node => {
|
|
1785
1465
|
if (includeNull)
|
|
@@ -1835,6 +1515,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1835
1515
|
dfs(startNode);
|
|
1836
1516
|
}
|
|
1837
1517
|
else {
|
|
1518
|
+
// Iterative
|
|
1838
1519
|
const stack = [{ opt: DFSOperation.VISIT, node: startNode }];
|
|
1839
1520
|
const pushLeft = (cur) => {
|
|
1840
1521
|
if (shouldVisitLeft(cur.node))
|
|
@@ -1862,6 +1543,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1862
1543
|
}
|
|
1863
1544
|
}
|
|
1864
1545
|
else {
|
|
1546
|
+
// VISIT
|
|
1865
1547
|
switch (pattern) {
|
|
1866
1548
|
case 'IN':
|
|
1867
1549
|
pushRight(cur);
|
|
@@ -1885,19 +1567,11 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1885
1567
|
return ans;
|
|
1886
1568
|
}
|
|
1887
1569
|
/**
|
|
1888
|
-
*
|
|
1889
|
-
* Space
|
|
1570
|
+
* (Protected) Gets the iterator for the tree (default in-order).
|
|
1571
|
+
* @remarks Time O(N) for full iteration. O(H) to get the first element. Space O(H) for the iterative stack. O(H) for recursive stack.
|
|
1890
1572
|
*
|
|
1891
|
-
*
|
|
1892
|
-
*
|
|
1893
|
-
* @param node - The `node` parameter in the `_getIterator` method represents the current node being
|
|
1894
|
-
* processed during iteration. It is initially set to the root node of the data structure (or the
|
|
1895
|
-
* node passed as an argument), and then it is traversed through the data structure based on the
|
|
1896
|
-
* iteration type specified (`ITER
|
|
1897
|
-
* @returns The `_getIterator` method returns an IterableIterator containing key-value pairs of nodes
|
|
1898
|
-
* in a binary tree structure. The method uses an iterative approach to traverse the tree based on
|
|
1899
|
-
* the `iterationType` property. If the `iterationType` is set to 'ITERATIVE', the method uses a
|
|
1900
|
-
* stack to perform an in-order traversal of the tree. If the `iterationType` is not 'ITERATIVE
|
|
1573
|
+
* @param [node=this._root] - The node to start iteration from.
|
|
1574
|
+
* @returns An iterator for [key, value] pairs.
|
|
1901
1575
|
*/
|
|
1902
1576
|
*_getIterator(node = this._root) {
|
|
1903
1577
|
if (!node)
|
|
@@ -1906,21 +1580,25 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1906
1580
|
const stack = [];
|
|
1907
1581
|
let current = node;
|
|
1908
1582
|
while (current || stack.length > 0) {
|
|
1583
|
+
// Go to the leftmost node
|
|
1909
1584
|
while (this.isRealNode(current)) {
|
|
1910
1585
|
stack.push(current);
|
|
1911
1586
|
current = current.left;
|
|
1912
1587
|
}
|
|
1588
|
+
// Visit the node
|
|
1913
1589
|
current = stack.pop();
|
|
1914
1590
|
if (this.isRealNode(current)) {
|
|
1915
1591
|
if (this._isMapMode)
|
|
1916
1592
|
yield [current.key, this._store.get(current.key)];
|
|
1917
1593
|
else
|
|
1918
1594
|
yield [current.key, current.value];
|
|
1595
|
+
// Move to the right subtree
|
|
1919
1596
|
current = current.right;
|
|
1920
1597
|
}
|
|
1921
1598
|
}
|
|
1922
1599
|
}
|
|
1923
1600
|
else {
|
|
1601
|
+
// Recursive in-order traversal
|
|
1924
1602
|
if (node.left && this.isRealNode(node)) {
|
|
1925
1603
|
yield* this[Symbol.iterator](node.left);
|
|
1926
1604
|
}
|
|
@@ -1934,24 +1612,112 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1934
1612
|
}
|
|
1935
1613
|
}
|
|
1936
1614
|
/**
|
|
1937
|
-
*
|
|
1938
|
-
*
|
|
1615
|
+
* (Protected) Default callback function, returns the node's key.
|
|
1616
|
+
* @remarks Time O(1)
|
|
1617
|
+
*
|
|
1618
|
+
* @param node - The node.
|
|
1619
|
+
* @returns The node's key or undefined.
|
|
1620
|
+
*/
|
|
1621
|
+
_DEFAULT_NODE_CALLBACK = (node) => (node ? node.key : undefined);
|
|
1622
|
+
/**
|
|
1623
|
+
* (Protected) Snapshots the current tree's configuration options.
|
|
1624
|
+
* @remarks Time O(1)
|
|
1625
|
+
*
|
|
1626
|
+
* @template TK, TV, TR - Generic types for the options.
|
|
1627
|
+
* @returns The options object.
|
|
1628
|
+
*/
|
|
1629
|
+
_snapshotOptions() {
|
|
1630
|
+
return {
|
|
1631
|
+
iterationType: this.iterationType,
|
|
1632
|
+
toEntryFn: this.toEntryFn,
|
|
1633
|
+
isMapMode: this.isMapMode,
|
|
1634
|
+
isDuplicate: this.isDuplicate
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* (Protected) Creates a new, empty instance of the same tree constructor.
|
|
1639
|
+
* @remarks Time O(1)
|
|
1640
|
+
*
|
|
1641
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
1642
|
+
* @param [options] - Options for the new tree.
|
|
1643
|
+
* @returns A new, empty tree.
|
|
1644
|
+
*/
|
|
1645
|
+
_createInstance(options) {
|
|
1646
|
+
const Ctor = this.constructor;
|
|
1647
|
+
return new Ctor([], { ...this._snapshotOptions(), ...(options ?? {}) });
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* (Protected) Creates a new instance of the same tree constructor, potentially with different generic types.
|
|
1651
|
+
* @remarks Time O(N) (or as per constructor) due to processing the iterable.
|
|
1939
1652
|
*
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1942
|
-
* @param
|
|
1943
|
-
*
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1653
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
1654
|
+
* @param [iter=[]] - An iterable to populate the new tree.
|
|
1655
|
+
* @param [options] - Options for the new tree.
|
|
1656
|
+
* @returns A new tree.
|
|
1657
|
+
*/
|
|
1658
|
+
_createLike(iter = [], options) {
|
|
1659
|
+
const Ctor = this.constructor;
|
|
1660
|
+
return new Ctor(iter, { ...this._snapshotOptions(), ...(options ?? {}) });
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* (Protected) Converts a key, node, or entry into a standardized [node, value] tuple.
|
|
1664
|
+
* @remarks Time O(1)
|
|
1665
|
+
*
|
|
1666
|
+
* @param keyNodeOrEntry - The input item.
|
|
1667
|
+
* @param [value] - An optional value (used if input is just a key).
|
|
1668
|
+
* @returns A tuple of [node, value].
|
|
1669
|
+
*/
|
|
1670
|
+
_keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value) {
|
|
1671
|
+
if (keyNodeOrEntry === undefined)
|
|
1672
|
+
return [undefined, undefined];
|
|
1673
|
+
if (keyNodeOrEntry === null)
|
|
1674
|
+
return [null, undefined];
|
|
1675
|
+
if (this.isNode(keyNodeOrEntry))
|
|
1676
|
+
return [keyNodeOrEntry, value];
|
|
1677
|
+
if (this.isEntry(keyNodeOrEntry)) {
|
|
1678
|
+
const [key, entryValue] = keyNodeOrEntry;
|
|
1679
|
+
if (key === undefined)
|
|
1680
|
+
return [undefined, undefined];
|
|
1681
|
+
else if (key === null)
|
|
1682
|
+
return [null, undefined];
|
|
1683
|
+
const finalValue = value ?? entryValue;
|
|
1684
|
+
return [this._createNode(key, finalValue), finalValue];
|
|
1685
|
+
}
|
|
1686
|
+
return [this._createNode(keyNodeOrEntry, value), value];
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* (Protected) Helper for cloning. Performs a BFS and adds all nodes to the new tree.
|
|
1690
|
+
* @remarks Time O(N * M) (O(N) BFS + O(M) `add` for each node).
|
|
1691
|
+
*
|
|
1692
|
+
* @param cloned - The new, empty tree instance to populate.
|
|
1693
|
+
*/
|
|
1694
|
+
_clone(cloned) {
|
|
1695
|
+
// Use BFS with nulls to preserve the tree structure
|
|
1696
|
+
this.bfs(node => {
|
|
1697
|
+
if (node === null)
|
|
1698
|
+
cloned.add(null);
|
|
1699
|
+
else {
|
|
1700
|
+
if (this._isMapMode)
|
|
1701
|
+
cloned.add([node.key, this._store.get(node.key)]);
|
|
1702
|
+
else
|
|
1703
|
+
cloned.add([node.key, node.value]);
|
|
1704
|
+
}
|
|
1705
|
+
}, this._root, this.iterationType, true // Include nulls
|
|
1706
|
+
);
|
|
1707
|
+
if (this._isMapMode)
|
|
1708
|
+
cloned._store = this._store;
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* (Protected) Recursive helper for `toVisual`.
|
|
1712
|
+
* @remarks Time O(N), Space O(N*H) or O(N^2)
|
|
1713
|
+
*
|
|
1714
|
+
* @param node - The current node.
|
|
1715
|
+
* @param options - Print options.
|
|
1716
|
+
* @returns Layout information for this subtree.
|
|
1950
1717
|
*/
|
|
1951
1718
|
_displayAux(node, options) {
|
|
1952
1719
|
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
1953
|
-
const emptyDisplayLayout = [['─'], 1, 0, 0];
|
|
1954
|
-
// Check if node is null or undefined or key is NaN
|
|
1720
|
+
const emptyDisplayLayout = [['─'], 1, 0, 0]; // Represents an empty spot
|
|
1955
1721
|
if (node === null && !isShowNull) {
|
|
1956
1722
|
return emptyDisplayLayout;
|
|
1957
1723
|
}
|
|
@@ -1962,15 +1728,20 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
1962
1728
|
return emptyDisplayLayout;
|
|
1963
1729
|
}
|
|
1964
1730
|
else if (node !== null && node !== undefined) {
|
|
1965
|
-
//
|
|
1731
|
+
// Real node
|
|
1966
1732
|
const key = node.key, line = this.isNIL(node) ? 'S' : String(key), width = line.length;
|
|
1967
1733
|
return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options));
|
|
1968
1734
|
}
|
|
1969
1735
|
else {
|
|
1970
|
-
//
|
|
1736
|
+
// Null or Undefined
|
|
1971
1737
|
const line = node === undefined ? 'U' : 'N', width = line.length;
|
|
1738
|
+
// Treat as a leaf
|
|
1972
1739
|
return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0]);
|
|
1973
1740
|
}
|
|
1741
|
+
/**
|
|
1742
|
+
* (Inner) Builds the display lines for a node.
|
|
1743
|
+
* @remarks Time/Space: Proportional to the width and height of the subtrees.
|
|
1744
|
+
*/
|
|
1974
1745
|
function _buildNodeDisplay(line, width, left, right) {
|
|
1975
1746
|
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
|
|
1976
1747
|
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
|
|
@@ -2000,32 +1771,26 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2000
1771
|
];
|
|
2001
1772
|
}
|
|
2002
1773
|
}
|
|
2003
|
-
_DEFAULT_NODE_CALLBACK = (node) => (node ? node.key : undefined);
|
|
2004
1774
|
/**
|
|
2005
|
-
*
|
|
2006
|
-
*
|
|
1775
|
+
* (Protected) Swaps the key/value properties of two nodes.
|
|
1776
|
+
* @remarks Time O(1)
|
|
2007
1777
|
*
|
|
2008
|
-
*
|
|
2009
|
-
* @param
|
|
2010
|
-
* `
|
|
2011
|
-
* properties, or it can be of type R.
|
|
2012
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } destNode - The `destNode` parameter in the
|
|
2013
|
-
* `_swapProperties` method represents the node or entry where the properties will be swapped with
|
|
2014
|
-
* the `srcNode`. It can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. The method ensures that
|
|
2015
|
-
* both `srcNode
|
|
2016
|
-
* @returns The `_swapProperties` method returns either the `destNode` with its key and value swapped
|
|
2017
|
-
* with the `srcNode`, or `undefined` if either `srcNode` or `destNode` is falsy.
|
|
1778
|
+
* @param srcNode - The source node.
|
|
1779
|
+
* @param destNode - The destination node.
|
|
1780
|
+
* @returns The `destNode` (now holding `srcNode`'s properties).
|
|
2018
1781
|
*/
|
|
2019
1782
|
_swapProperties(srcNode, destNode) {
|
|
2020
1783
|
srcNode = this.ensureNode(srcNode);
|
|
2021
1784
|
destNode = this.ensureNode(destNode);
|
|
2022
1785
|
if (srcNode && destNode) {
|
|
2023
1786
|
const { key, value } = destNode;
|
|
2024
|
-
const tempNode = this.
|
|
1787
|
+
const tempNode = this._createNode(key, value); // Use a temp node to hold dest properties
|
|
2025
1788
|
if (tempNode) {
|
|
1789
|
+
// Copy src to dest
|
|
2026
1790
|
destNode.key = srcNode.key;
|
|
2027
1791
|
if (!this._isMapMode)
|
|
2028
1792
|
destNode.value = srcNode.value;
|
|
1793
|
+
// Copy temp (original dest) to src
|
|
2029
1794
|
srcNode.key = tempNode.key;
|
|
2030
1795
|
if (!this._isMapMode)
|
|
2031
1796
|
srcNode.value = tempNode.value;
|
|
@@ -2035,18 +1800,12 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2035
1800
|
return undefined;
|
|
2036
1801
|
}
|
|
2037
1802
|
/**
|
|
2038
|
-
*
|
|
2039
|
-
*
|
|
1803
|
+
* (Protected) Replaces a node in the tree with a new node, maintaining children and parent links.
|
|
1804
|
+
* @remarks Time O(1)
|
|
2040
1805
|
*
|
|
2041
|
-
*
|
|
2042
|
-
* @param
|
|
2043
|
-
*
|
|
2044
|
-
* @param {BinaryTreeNode<K, V>} newNode - The `newNode` parameter in the `_replaceNode` function represents the node
|
|
2045
|
-
* that will replace the `oldNode` in a tree data structure. This function is responsible for
|
|
2046
|
-
* updating the parent, left child, right child, and root (if necessary) references when replacing a
|
|
2047
|
-
* node in the tree.
|
|
2048
|
-
* @returns The method `_replaceNode` is returning the `newNode` that was passed as a parameter after
|
|
2049
|
-
* replacing the `oldNode` with it in the binary tree structure.
|
|
1806
|
+
* @param oldNode - The node to be replaced.
|
|
1807
|
+
* @param newNode - The node to insert.
|
|
1808
|
+
* @returns The `newNode`.
|
|
2050
1809
|
*/
|
|
2051
1810
|
_replaceNode(oldNode, newNode) {
|
|
2052
1811
|
if (oldNode.parent) {
|
|
@@ -2066,13 +1825,10 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2066
1825
|
return newNode;
|
|
2067
1826
|
}
|
|
2068
1827
|
/**
|
|
2069
|
-
*
|
|
2070
|
-
*
|
|
1828
|
+
* (Protected) Sets the root node and clears its parent reference.
|
|
1829
|
+
* @remarks Time O(1)
|
|
2071
1830
|
*
|
|
2072
|
-
*
|
|
2073
|
-
* of the previous root node.
|
|
2074
|
-
* @param v - The parameter `v` in the `_setRoot` method is of type `BinaryTreeNode<K, V> | null | undefined`, which means
|
|
2075
|
-
* it can either be an optional `BinaryTreeNode<K, V>` type or `null`.
|
|
1831
|
+
* @param v - The node to set as root.
|
|
2076
1832
|
*/
|
|
2077
1833
|
_setRoot(v) {
|
|
2078
1834
|
if (v) {
|
|
@@ -2080,18 +1836,6 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2080
1836
|
}
|
|
2081
1837
|
this._root = v;
|
|
2082
1838
|
}
|
|
2083
|
-
/**
|
|
2084
|
-
* Time Complexity: O(1)
|
|
2085
|
-
* Space Complexity: O(1)
|
|
2086
|
-
*
|
|
2087
|
-
* The function `_ensurePredicate` in TypeScript ensures that the input is converted into a valid
|
|
2088
|
-
* predicate function for a binary tree node.
|
|
2089
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate - The
|
|
2090
|
-
* `_ensurePredicate` method in the provided code snippet is responsible for ensuring that the input
|
|
2091
|
-
* parameter `keyNodeEntryOrPredicate` is transformed into a valid predicate function that can be
|
|
2092
|
-
* used for filtering nodes in a binary tree.
|
|
2093
|
-
* @returns A NodePredicate<BinaryTreeNode<K, V>> function is being returned.
|
|
2094
|
-
*/
|
|
2095
1839
|
_ensurePredicate(keyNodeEntryOrPredicate) {
|
|
2096
1840
|
if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === undefined)
|
|
2097
1841
|
return (node) => (node ? false : false);
|
|
@@ -2107,6 +1851,7 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2107
1851
|
return node.key === key;
|
|
2108
1852
|
};
|
|
2109
1853
|
}
|
|
1854
|
+
// Assume it's a key
|
|
2110
1855
|
return (node) => {
|
|
2111
1856
|
if (!node)
|
|
2112
1857
|
return false;
|
|
@@ -2114,32 +1859,21 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2114
1859
|
};
|
|
2115
1860
|
}
|
|
2116
1861
|
/**
|
|
2117
|
-
*
|
|
2118
|
-
*
|
|
1862
|
+
* (Protected) Checks if an item is a predicate function.
|
|
1863
|
+
* @remarks Time O(1)
|
|
2119
1864
|
*
|
|
2120
|
-
*
|
|
2121
|
-
* @
|
|
2122
|
-
* of value. In this context, the function `_isPredicate` is checking if `p` is a function that
|
|
2123
|
-
* satisfies the type `NodePredicate<BinaryTreeNode<K, V>>`.
|
|
2124
|
-
* @returns The function is checking if the input `p` is a function and returning a boolean value
|
|
2125
|
-
* based on that check. If `p` is a function, it will return `true`, indicating that `p` is a
|
|
2126
|
-
* predicate function for a binary tree node. If `p` is not a function, it will return `false`.
|
|
1865
|
+
* @param p - The item to check.
|
|
1866
|
+
* @returns True if it's a function.
|
|
2127
1867
|
*/
|
|
2128
1868
|
_isPredicate(p) {
|
|
2129
1869
|
return typeof p === 'function';
|
|
2130
1870
|
}
|
|
2131
1871
|
/**
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
1872
|
+
* (Protected) Extracts the key from a key, node, or entry.
|
|
1873
|
+
* @remarks Time O(1)
|
|
2134
1874
|
*
|
|
2135
|
-
*
|
|
2136
|
-
*
|
|
2137
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `_extractKey` method you provided is a
|
|
2138
|
-
* TypeScript method that takes in a parameter `keyNodeOrEntry` of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `,
|
|
2139
|
-
* where `BTNRep` is a generic type with keys `K`, `V`, and `BinaryTreeNode<K, V>`, and `
|
|
2140
|
-
* @returns The `_extractKey` method returns the key value extracted from the `keyNodeOrEntry`
|
|
2141
|
-
* parameter. The return value can be a key value of type `K`, `null`, or `undefined`, depending on
|
|
2142
|
-
* the conditions checked in the method.
|
|
1875
|
+
* @param keyNodeOrEntry - The item.
|
|
1876
|
+
* @returns The extracted key.
|
|
2143
1877
|
*/
|
|
2144
1878
|
_extractKey(keyNodeOrEntry) {
|
|
2145
1879
|
if (keyNodeOrEntry === null)
|
|
@@ -2155,41 +1889,31 @@ export class BinaryTree extends IterableEntryBase {
|
|
|
2155
1889
|
return keyNodeOrEntry;
|
|
2156
1890
|
}
|
|
2157
1891
|
/**
|
|
2158
|
-
*
|
|
2159
|
-
*
|
|
1892
|
+
* (Protected) Sets a value in the external store (Map mode).
|
|
1893
|
+
* @remarks Time O(1) (average for Map.set).
|
|
2160
1894
|
*
|
|
2161
|
-
*
|
|
2162
|
-
* value
|
|
2163
|
-
* @
|
|
2164
|
-
* `undefined`.
|
|
2165
|
-
* @param {V | undefined} value - The `value` parameter in the `_setValue` method can be of type `V`
|
|
2166
|
-
* or `undefined`.
|
|
2167
|
-
* @returns The method `_setValue` returns `false` if either the `key` is `null` or `undefined`, or
|
|
2168
|
-
* if the `value` is `undefined`. Otherwise, it returns the result of calling the `set` method on the
|
|
2169
|
-
* `_store` object with the `key` and `value` arguments.
|
|
1895
|
+
* @param key - The key.
|
|
1896
|
+
* @param value - The value.
|
|
1897
|
+
* @returns True if successful.
|
|
2170
1898
|
*/
|
|
2171
1899
|
_setValue(key, value) {
|
|
2172
1900
|
if (key === null || key === undefined)
|
|
2173
1901
|
return false;
|
|
2174
1902
|
if (value === undefined)
|
|
2175
|
-
return false;
|
|
1903
|
+
return false; // Or allow setting undefined?
|
|
2176
1904
|
return this._store.set(key, value);
|
|
2177
1905
|
}
|
|
2178
1906
|
/**
|
|
2179
|
-
*
|
|
2180
|
-
*
|
|
2181
|
-
*
|
|
2182
|
-
* The _clearNodes function sets the root node to undefined and resets the size to 0.
|
|
1907
|
+
* (Protected) Clears all nodes from the tree.
|
|
1908
|
+
* @remarks Time O(1)
|
|
2183
1909
|
*/
|
|
2184
1910
|
_clearNodes() {
|
|
2185
1911
|
this._setRoot(undefined);
|
|
2186
1912
|
this._size = 0;
|
|
2187
1913
|
}
|
|
2188
1914
|
/**
|
|
2189
|
-
*
|
|
2190
|
-
*
|
|
2191
|
-
*
|
|
2192
|
-
* The _clearValues function clears all values stored in the _store object.
|
|
1915
|
+
* (Protected) Clears all values from the external store.
|
|
1916
|
+
* @remarks Time O(N)
|
|
2193
1917
|
*/
|
|
2194
1918
|
_clearValues() {
|
|
2195
1919
|
this._store.clear();
|