avl-tree-typed 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/index.js +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/data-structures/base/iterable-element-base.js +149 -107
- package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/data-structures/base/linear-base.d.ts +250 -192
- package/dist/data-structures/base/linear-base.js +137 -274
- package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
- package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
- package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/data-structures/binary-tree/avl-tree.js +208 -195
- package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/data-structures/binary-tree/binary-tree.js +612 -879
- package/dist/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/data-structures/binary-tree/bst.js +505 -481
- package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
- package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/data-structures/binary-tree/tree-counter.js +172 -203
- package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
- package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/data-structures/graph/abstract-graph.js +267 -237
- package/dist/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/data-structures/graph/directed-graph.js +146 -233
- package/dist/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/data-structures/graph/map-graph.js +56 -59
- package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/data-structures/graph/undirected-graph.js +129 -149
- package/dist/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/data-structures/hash/hash-map.js +270 -457
- package/dist/data-structures/heap/heap.d.ts +214 -289
- package/dist/data-structures/heap/heap.js +340 -349
- package/dist/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/data-structures/heap/max-heap.js +11 -66
- package/dist/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/data-structures/heap/min-heap.js +11 -66
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
- package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
- package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/data-structures/queue/deque.d.ts +227 -254
- package/dist/data-structures/queue/deque.js +309 -348
- package/dist/data-structures/queue/queue.d.ts +180 -201
- package/dist/data-structures/queue/queue.js +265 -248
- package/dist/data-structures/stack/stack.d.ts +124 -102
- package/dist/data-structures/stack/stack.js +181 -125
- package/dist/data-structures/trie/trie.d.ts +164 -165
- package/dist/data-structures/trie/trie.js +189 -172
- package/dist/interfaces/binary-tree.d.ts +56 -6
- package/dist/interfaces/graph.d.ts +16 -0
- package/dist/types/data-structures/base/base.d.ts +1 -1
- package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/types/utils/utils.d.ts +6 -6
- package/dist/utils/number.js +1 -2
- package/dist/utils/utils.d.ts +110 -49
- package/dist/utils/utils.js +149 -74
- package/package.json +15 -15
- 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 +681 -905
- package/src/data-structures/binary-tree/bst.ts +568 -570
- package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
- package/src/data-structures/binary-tree/tree-counter.ts +199 -218
- package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
- package/src/data-structures/graph/abstract-graph.ts +339 -264
- package/src/data-structures/graph/directed-graph.ts +146 -236
- package/src/data-structures/graph/map-graph.ts +63 -60
- package/src/data-structures/graph/undirected-graph.ts +129 -152
- package/src/data-structures/hash/hash-map.ts +274 -496
- package/src/data-structures/heap/heap.ts +389 -402
- package/src/data-structures/heap/max-heap.ts +12 -76
- package/src/data-structures/heap/min-heap.ts +13 -76
- package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
- package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
- package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
- package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
- package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
- package/src/data-structures/priority-queue/priority-queue.ts +3 -92
- package/src/data-structures/queue/deque.ts +381 -357
- package/src/data-structures/queue/queue.ts +310 -264
- package/src/data-structures/stack/stack.ts +217 -131
- package/src/data-structures/trie/trie.ts +240 -175
- package/src/interfaces/binary-tree.ts +240 -6
- package/src/interfaces/graph.ts +37 -0
- package/src/types/data-structures/base/base.ts +5 -5
- package/src/types/data-structures/graph/abstract-graph.ts +5 -0
- package/src/types/utils/utils.ts +9 -5
- package/src/utils/utils.ts +152 -86
|
@@ -21,18 +21,18 @@ import type {
|
|
|
21
21
|
NodePredicate,
|
|
22
22
|
OptNodeOrNull,
|
|
23
23
|
RBTNColor,
|
|
24
|
-
ToEntryFn
|
|
24
|
+
ToEntryFn,
|
|
25
|
+
Trampoline
|
|
25
26
|
} from '../../types';
|
|
26
27
|
import { IBinaryTree } from '../../interfaces';
|
|
27
|
-
import { isComparable,
|
|
28
|
+
import { isComparable, makeTrampoline, makeTrampolineThunk } from '../../utils';
|
|
28
29
|
import { Queue } from '../queue';
|
|
29
30
|
import { IterableEntryBase } from '../base';
|
|
30
31
|
import { DFSOperation, Range } from '../../common';
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @template V - The type of
|
|
35
|
-
* @template BinaryTreeNode<K, V> - The type of the family relationship in the binary tree.
|
|
34
|
+
* @template K - The type of the key.
|
|
35
|
+
* @template V - The type of the value.
|
|
36
36
|
*/
|
|
37
37
|
export class BinaryTreeNode<K = any, V = any> {
|
|
38
38
|
key: K;
|
|
@@ -40,12 +40,11 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
40
40
|
parent?: BinaryTreeNode<K, V> = undefined;
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
* @
|
|
45
|
-
*
|
|
46
|
-
* @param
|
|
47
|
-
*
|
|
48
|
-
* default to `undefined`.
|
|
43
|
+
* Creates an instance of BinaryTreeNode.
|
|
44
|
+
* @remarks Time O(1), Space O(1)
|
|
45
|
+
*
|
|
46
|
+
* @param key - The key of the node.
|
|
47
|
+
* @param [value] - The value associated with the key.
|
|
49
48
|
*/
|
|
50
49
|
constructor(key: K, value?: V) {
|
|
51
50
|
this.key = key;
|
|
@@ -54,10 +53,22 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
54
53
|
|
|
55
54
|
_left?: BinaryTreeNode<K, V> | null | undefined = undefined;
|
|
56
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Gets the left child of the node.
|
|
58
|
+
* @remarks Time O(1), Space O(1)
|
|
59
|
+
*
|
|
60
|
+
* @returns The left child.
|
|
61
|
+
*/
|
|
57
62
|
get left(): BinaryTreeNode<K, V> | null | undefined {
|
|
58
63
|
return this._left;
|
|
59
64
|
}
|
|
60
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Sets the left child of the node and updates its parent reference.
|
|
68
|
+
* @remarks Time O(1), Space O(1)
|
|
69
|
+
*
|
|
70
|
+
* @param v - The node to set as the left child.
|
|
71
|
+
*/
|
|
61
72
|
set left(v: BinaryTreeNode<K, V> | null | undefined) {
|
|
62
73
|
if (v) {
|
|
63
74
|
v.parent = this as unknown as BinaryTreeNode<K, V>;
|
|
@@ -67,10 +78,22 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
67
78
|
|
|
68
79
|
_right?: BinaryTreeNode<K, V> | null | undefined = undefined;
|
|
69
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Gets the right child of the node.
|
|
83
|
+
* @remarks Time O(1), Space O(1)
|
|
84
|
+
*
|
|
85
|
+
* @returns The right child.
|
|
86
|
+
*/
|
|
70
87
|
get right(): BinaryTreeNode<K, V> | null | undefined {
|
|
71
88
|
return this._right;
|
|
72
89
|
}
|
|
73
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Sets the right child of the node and updates its parent reference.
|
|
93
|
+
* @remarks Time O(1), Space O(1)
|
|
94
|
+
*
|
|
95
|
+
* @param v - The node to set as the right child.
|
|
96
|
+
*/
|
|
74
97
|
set right(v: BinaryTreeNode<K, V> | null | undefined) {
|
|
75
98
|
if (v) {
|
|
76
99
|
v.parent = this;
|
|
@@ -80,34 +103,76 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
80
103
|
|
|
81
104
|
_height: number = 0;
|
|
82
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Gets the height of the node (used in self-balancing trees).
|
|
108
|
+
* @remarks Time O(1), Space O(1)
|
|
109
|
+
*
|
|
110
|
+
* @returns The height.
|
|
111
|
+
*/
|
|
83
112
|
get height(): number {
|
|
84
113
|
return this._height;
|
|
85
114
|
}
|
|
86
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Sets the height of the node.
|
|
118
|
+
* @remarks Time O(1), Space O(1)
|
|
119
|
+
*
|
|
120
|
+
* @param value - The new height.
|
|
121
|
+
*/
|
|
87
122
|
set height(value: number) {
|
|
88
123
|
this._height = value;
|
|
89
124
|
}
|
|
90
125
|
|
|
91
126
|
_color: RBTNColor = 'BLACK';
|
|
92
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Gets the color of the node (used in Red-Black trees).
|
|
130
|
+
* @remarks Time O(1), Space O(1)
|
|
131
|
+
*
|
|
132
|
+
* @returns The node's color.
|
|
133
|
+
*/
|
|
93
134
|
get color(): RBTNColor {
|
|
94
135
|
return this._color;
|
|
95
136
|
}
|
|
96
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Sets the color of the node.
|
|
140
|
+
* @remarks Time O(1), Space O(1)
|
|
141
|
+
*
|
|
142
|
+
* @param value - The new color.
|
|
143
|
+
*/
|
|
97
144
|
set color(value: RBTNColor) {
|
|
98
145
|
this._color = value;
|
|
99
146
|
}
|
|
100
147
|
|
|
101
148
|
_count: number = 1;
|
|
102
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Gets the count of nodes in the subtree rooted at this node (used in order-statistic trees).
|
|
152
|
+
* @remarks Time O(1), Space O(1)
|
|
153
|
+
*
|
|
154
|
+
* @returns The subtree node count.
|
|
155
|
+
*/
|
|
103
156
|
get count(): number {
|
|
104
157
|
return this._count;
|
|
105
158
|
}
|
|
106
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Sets the count of nodes in the subtree.
|
|
162
|
+
* @remarks Time O(1), Space O(1)
|
|
163
|
+
*
|
|
164
|
+
* @param value - The new count.
|
|
165
|
+
*/
|
|
107
166
|
set count(value: number) {
|
|
108
167
|
this._count = value;
|
|
109
168
|
}
|
|
110
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Gets the position of the node relative to its parent.
|
|
172
|
+
* @remarks Time O(1), Space O(1)
|
|
173
|
+
*
|
|
174
|
+
* @returns The family position (e.g., 'ROOT', 'LEFT', 'RIGHT').
|
|
175
|
+
*/
|
|
111
176
|
get familyPosition(): FamilyPosition {
|
|
112
177
|
if (!this.parent) {
|
|
113
178
|
return this.left || this.right ? 'ROOT' : 'ISOLATED';
|
|
@@ -124,6 +189,15 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
124
189
|
}
|
|
125
190
|
|
|
126
191
|
/**
|
|
192
|
+
* A general Binary Tree implementation.
|
|
193
|
+
*
|
|
194
|
+
* @remarks
|
|
195
|
+
* This class implements a basic Binary Tree, not a Binary Search Tree.
|
|
196
|
+
* The `add` operation inserts nodes level-by-level (BFS) into the first available slot.
|
|
197
|
+
*
|
|
198
|
+
* @template K - The type of the key.
|
|
199
|
+
* @template V - The type of the value.
|
|
200
|
+
* @template R - The type of the raw data object (if using `toEntryFn`).
|
|
127
201
|
* 1. Two Children Maximum: Each node has at most two children.
|
|
128
202
|
* 2. Left and Right Children: Nodes have distinct left and right children.
|
|
129
203
|
* 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree.
|
|
@@ -192,20 +266,18 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
192
266
|
*
|
|
193
267
|
* console.log(evaluate(expressionTree.root)); // -27
|
|
194
268
|
*/
|
|
195
|
-
export class BinaryTree<K = any, V = any, R
|
|
269
|
+
export class BinaryTree<K = any, V = any, R extends object = object>
|
|
196
270
|
extends IterableEntryBase<K, V | undefined>
|
|
197
|
-
implements IBinaryTree<K, V, R
|
|
271
|
+
implements IBinaryTree<K, V, R>
|
|
198
272
|
{
|
|
199
273
|
iterationType: IterationType = 'ITERATIVE';
|
|
200
274
|
|
|
201
275
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* @param [options] - The `options` parameter in the constructor is an optional object that can
|
|
208
|
-
* contain the following properties:
|
|
276
|
+
* Creates an instance of BinaryTree.
|
|
277
|
+
* @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.
|
|
278
|
+
*
|
|
279
|
+
* @param [keysNodesEntriesOrRaws=[]] - An iterable of items to add.
|
|
280
|
+
* @param [options] - Configuration options for the tree.
|
|
209
281
|
*/
|
|
210
282
|
constructor(
|
|
211
283
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -228,96 +300,118 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
228
300
|
|
|
229
301
|
protected _isMapMode = true;
|
|
230
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Gets whether the tree is in Map mode.
|
|
305
|
+
* @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)
|
|
306
|
+
*
|
|
307
|
+
* @returns True if in Map mode, false otherwise.
|
|
308
|
+
*/
|
|
231
309
|
get isMapMode() {
|
|
232
310
|
return this._isMapMode;
|
|
233
311
|
}
|
|
234
312
|
|
|
235
313
|
protected _isDuplicate = false;
|
|
236
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Gets whether the tree allows duplicate keys.
|
|
317
|
+
* @remarks Time O(1)
|
|
318
|
+
*
|
|
319
|
+
* @returns True if duplicates are allowed, false otherwise.
|
|
320
|
+
*/
|
|
237
321
|
get isDuplicate() {
|
|
238
322
|
return this._isDuplicate;
|
|
239
323
|
}
|
|
240
324
|
|
|
241
325
|
protected _store = new Map<K, V | undefined>();
|
|
242
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Gets the external value store (used in Map mode).
|
|
329
|
+
* @remarks Time O(1)
|
|
330
|
+
*
|
|
331
|
+
* @returns The map storing key-value pairs.
|
|
332
|
+
*/
|
|
243
333
|
get store() {
|
|
244
334
|
return this._store;
|
|
245
335
|
}
|
|
246
336
|
|
|
247
337
|
protected _root?: BinaryTreeNode<K, V> | null | undefined;
|
|
248
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Gets the root node of the tree.
|
|
341
|
+
* @remarks Time O(1)
|
|
342
|
+
*
|
|
343
|
+
* @returns The root node.
|
|
344
|
+
*/
|
|
249
345
|
get root(): BinaryTreeNode<K, V> | null | undefined {
|
|
250
346
|
return this._root;
|
|
251
347
|
}
|
|
252
348
|
|
|
253
349
|
protected _size: number = 0;
|
|
254
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Gets the number of nodes in the tree.
|
|
353
|
+
* @remarks Time O(1)
|
|
354
|
+
*
|
|
355
|
+
* @returns The size of the tree.
|
|
356
|
+
*/
|
|
255
357
|
get size(): number {
|
|
256
358
|
return this._size;
|
|
257
359
|
}
|
|
258
360
|
|
|
259
361
|
protected _NIL: BinaryTreeNode<K, V> = new BinaryTreeNode<K, V>(NaN as K) as unknown as BinaryTreeNode<K, V>;
|
|
260
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Gets the sentinel NIL node (used in self-balancing trees like Red-Black Tree).
|
|
365
|
+
* @remarks Time O(1)
|
|
366
|
+
*
|
|
367
|
+
* @returns The NIL node.
|
|
368
|
+
*/
|
|
261
369
|
get NIL(): BinaryTreeNode<K, V> {
|
|
262
370
|
return this._NIL;
|
|
263
371
|
}
|
|
264
372
|
|
|
265
373
|
protected _toEntryFn?: ToEntryFn<K, V, R>;
|
|
266
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Gets the function used to convert raw data objects (R) into [key, value] entries.
|
|
377
|
+
* @remarks Time O(1)
|
|
378
|
+
*
|
|
379
|
+
* @returns The conversion function.
|
|
380
|
+
*/
|
|
267
381
|
get toEntryFn() {
|
|
268
382
|
return this._toEntryFn;
|
|
269
383
|
}
|
|
270
384
|
|
|
271
385
|
/**
|
|
272
|
-
*
|
|
273
|
-
*
|
|
386
|
+
* (Protected) Creates a new node.
|
|
387
|
+
* @remarks Time O(1), Space O(1)
|
|
274
388
|
*
|
|
275
|
-
* The
|
|
276
|
-
* @param
|
|
277
|
-
* @
|
|
278
|
-
* not required to be provided when calling the function. If a `value` is provided, it should be of
|
|
279
|
-
* type `V`, which is the type of the value associated with the node.
|
|
280
|
-
* @returns A new BinaryTreeNode instance with the provided key and value is being returned, casted
|
|
281
|
-
* as BinaryTreeNode<K, V>.
|
|
389
|
+
* @param key - The key for the new node.
|
|
390
|
+
* @param [value] - The value for the new node (used if not in Map mode).
|
|
391
|
+
* @returns The newly created node.
|
|
282
392
|
*/
|
|
283
|
-
|
|
393
|
+
_createNode(key: K, value?: V): BinaryTreeNode<K, V> {
|
|
284
394
|
return new BinaryTreeNode<K, V>(key, this._isMapMode ? undefined : value);
|
|
285
395
|
}
|
|
286
396
|
|
|
287
397
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
398
|
+
* Creates a new, empty tree of the same type and configuration.
|
|
399
|
+
* @remarks Time O(1) (excluding options cloning), Space O(1)
|
|
290
400
|
*
|
|
291
|
-
*
|
|
292
|
-
* @
|
|
293
|
-
* that allows you to provide partial configuration options for creating a binary tree. It is of type
|
|
294
|
-
* `Partial<BinaryTreeOptions<K, V, R>>`, which means you can pass in an object containing a subset
|
|
295
|
-
* of properties
|
|
296
|
-
* @returns A new instance of a binary tree with the specified options is being returned.
|
|
401
|
+
* @param [options] - Optional overrides for the new tree's options.
|
|
402
|
+
* @returns A new, empty tree instance.
|
|
297
403
|
*/
|
|
298
|
-
createTree(options?: BinaryTreeOptions<K, V, R
|
|
299
|
-
return
|
|
300
|
-
iterationType: this.iterationType,
|
|
301
|
-
isMapMode: this._isMapMode,
|
|
302
|
-
toEntryFn: this._toEntryFn,
|
|
303
|
-
...options
|
|
304
|
-
});
|
|
404
|
+
createTree(options?: Partial<BinaryTreeOptions<K, V, R>>): this {
|
|
405
|
+
return this._createInstance<K, V, R>(options);
|
|
305
406
|
}
|
|
306
407
|
|
|
307
408
|
/**
|
|
308
|
-
*
|
|
309
|
-
* Space
|
|
409
|
+
* Ensures the input is a node. If it's a key or entry, it searches for the node.
|
|
410
|
+
* @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).
|
|
310
411
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* @
|
|
314
|
-
* parameter in the `ensureNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It
|
|
315
|
-
* is used to determine whether the input is a key, node, entry, or raw data. The
|
|
316
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `ensureNode` function
|
|
317
|
-
* is used to specify the type of iteration to be performed. It has a default value of
|
|
318
|
-
* `this.iterationType` if not explicitly provided.
|
|
319
|
-
* @returns The `ensureNode` function returns either a node, `null`, or `undefined` based on the
|
|
320
|
-
* conditions specified in the code snippet.
|
|
412
|
+
* @param keyNodeOrEntry - The item to resolve to a node.
|
|
413
|
+
* @param [iterationType=this.iterationType] - The traversal method to use if searching.
|
|
414
|
+
* @returns The resolved node, or null/undefined if not found or input is null/undefined.
|
|
321
415
|
*/
|
|
322
416
|
ensureNode(
|
|
323
417
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -340,18 +434,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
340
434
|
}
|
|
341
435
|
|
|
342
436
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
437
|
+
* Checks if the given item is a `BinaryTreeNode` instance.
|
|
438
|
+
* @remarks Time O(1), Space O(1)
|
|
345
439
|
*
|
|
346
|
-
*
|
|
347
|
-
* @
|
|
348
|
-
* `keyNodeOrEntry` can be either a key, a node, an entry, or raw data. The function is
|
|
349
|
-
* checking if the input is an instance of a `BinaryTreeNode` and returning a boolean value
|
|
350
|
-
* accordingly.
|
|
351
|
-
* @returns The function `isNode` is checking if the input `keyNodeOrEntry` is an instance of
|
|
352
|
-
* `BinaryTreeNode`. If it is, the function returns `true`, indicating that the input is a node. If
|
|
353
|
-
* it is not an instance of `BinaryTreeNode`, the function returns `false`, indicating that the input
|
|
354
|
-
* is not a node.
|
|
440
|
+
* @param keyNodeOrEntry - The item to check.
|
|
441
|
+
* @returns True if it's a node, false otherwise.
|
|
355
442
|
*/
|
|
356
443
|
isNode(
|
|
357
444
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -360,14 +447,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
360
447
|
}
|
|
361
448
|
|
|
362
449
|
/**
|
|
363
|
-
*
|
|
364
|
-
*
|
|
450
|
+
* Checks if the given item is a raw data object (R) that needs conversion via `toEntryFn`.
|
|
451
|
+
* @remarks Time O(1), Space O(1)
|
|
365
452
|
*
|
|
366
|
-
*
|
|
367
|
-
* @
|
|
368
|
-
* @returns The function `isRaw` is checking if the `keyNodeEntryOrRaw` parameter is of type `R` by
|
|
369
|
-
* checking if it is an object. If the parameter is an object, the function will return `true`,
|
|
370
|
-
* indicating that it is of type `R`.
|
|
453
|
+
* @param keyNodeEntryOrRaw - The item to check.
|
|
454
|
+
* @returns True if it's a raw object, false otherwise.
|
|
371
455
|
*/
|
|
372
456
|
isRaw(
|
|
373
457
|
keyNodeEntryOrRaw: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R
|
|
@@ -376,17 +460,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
376
460
|
}
|
|
377
461
|
|
|
378
462
|
/**
|
|
379
|
-
*
|
|
380
|
-
*
|
|
463
|
+
* Checks if the given item is a "real" node (i.e., not null, undefined, or NIL).
|
|
464
|
+
* @remarks Time O(1), Space O(1)
|
|
381
465
|
*
|
|
382
|
-
*
|
|
383
|
-
* @
|
|
384
|
-
* parameter in the `isRealNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
|
|
385
|
-
* The function checks if the input parameter is a `BinaryTreeNode<K, V>` type by verifying if it is not equal
|
|
386
|
-
* @returns The function `isRealNode` is checking if the input `keyNodeOrEntry` is a valid
|
|
387
|
-
* node by comparing it to `this._NIL`, `null`, and `undefined`. If the input is not one of these
|
|
388
|
-
* values, it then calls the `isNode` method to further determine if the input is a node. The
|
|
389
|
-
* function will return a boolean value indicating whether the
|
|
466
|
+
* @param keyNodeOrEntry - The item to check.
|
|
467
|
+
* @returns True if it's a real node, false otherwise.
|
|
390
468
|
*/
|
|
391
469
|
isRealNode(
|
|
392
470
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -396,16 +474,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
396
474
|
}
|
|
397
475
|
|
|
398
476
|
/**
|
|
399
|
-
*
|
|
400
|
-
*
|
|
477
|
+
* Checks if the given item is either a "real" node or null.
|
|
478
|
+
* @remarks Time O(1), Space O(1)
|
|
401
479
|
*
|
|
402
|
-
*
|
|
403
|
-
* @
|
|
404
|
-
* `keyNodeOrEntry` in the `isRealNodeOrNull` function can be of type `BTNRep<K,
|
|
405
|
-
* V, BinaryTreeNode<K, V>>` or `R`. It is a union type that can either be a key, a node, an entry, or
|
|
406
|
-
* @returns The function `isRealNodeOrNull` is returning a boolean value. It checks if the input
|
|
407
|
-
* `keyNodeOrEntry` is either `null` or a real node, and returns `true` if it is a node or
|
|
408
|
-
* `null`, and `false` otherwise.
|
|
480
|
+
* @param keyNodeOrEntry - The item to check.
|
|
481
|
+
* @returns True if it's a real node or null, false otherwise.
|
|
409
482
|
*/
|
|
410
483
|
isRealNodeOrNull(
|
|
411
484
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -414,32 +487,22 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
414
487
|
}
|
|
415
488
|
|
|
416
489
|
/**
|
|
417
|
-
*
|
|
418
|
-
*
|
|
490
|
+
* Checks if the given item is the sentinel NIL node.
|
|
491
|
+
* @remarks Time O(1), Space O(1)
|
|
419
492
|
*
|
|
420
|
-
*
|
|
421
|
-
* @
|
|
422
|
-
* BinaryTreeNode<K, V>>
|
|
423
|
-
* @returns The function is checking if the `keyNodeOrEntry` parameter is equal to the `_NIL`
|
|
424
|
-
* property of the current object and returning a boolean value based on that comparison.
|
|
493
|
+
* @param keyNodeOrEntry - The item to check.
|
|
494
|
+
* @returns True if it's the NIL node, false otherwise.
|
|
425
495
|
*/
|
|
426
496
|
isNIL(keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined): boolean {
|
|
427
497
|
return keyNodeOrEntry === this._NIL;
|
|
428
498
|
}
|
|
429
499
|
|
|
430
500
|
/**
|
|
431
|
-
*
|
|
432
|
-
*
|
|
501
|
+
* Checks if the given item is a `Range` object.
|
|
502
|
+
* @remarks Time O(1), Space O(1)
|
|
433
503
|
*
|
|
434
|
-
*
|
|
435
|
-
* @
|
|
436
|
-
* - The `keyNodeEntryOrPredicate` parameter in the `isRange` function can be
|
|
437
|
-
* of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `NodePredicate<BinaryTreeNode<K, V>>`, or
|
|
438
|
-
* `Range<K>`. The function checks if the `keyNodeEntry
|
|
439
|
-
* @returns The `isRange` function is checking if the `keyNodeEntryOrPredicate` parameter is an
|
|
440
|
-
* instance of the `Range` class. If it is an instance of `Range`, the function will return `true`,
|
|
441
|
-
* indicating that the parameter is a `Range<K>`. If it is not an instance of `Range`, the function
|
|
442
|
-
* will return `false`.
|
|
504
|
+
* @param keyNodeEntryOrPredicate - The item to check.
|
|
505
|
+
* @returns True if it's a Range, false otherwise.
|
|
443
506
|
*/
|
|
444
507
|
isRange(
|
|
445
508
|
keyNodeEntryOrPredicate:
|
|
@@ -455,37 +518,25 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
455
518
|
}
|
|
456
519
|
|
|
457
520
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
521
|
+
* Checks if a node is a leaf (has no real children).
|
|
522
|
+
* @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`).
|
|
460
523
|
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
|
464
|
-
* `keyNodeOrEntry` can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It represents a
|
|
465
|
-
* key, node, entry, or raw data in a binary tree structure. The function `isLeaf` checks whether the
|
|
466
|
-
* provided
|
|
467
|
-
* @returns The function `isLeaf` returns a boolean value indicating whether the input
|
|
468
|
-
* `keyNodeOrEntry` is a leaf node in a binary tree.
|
|
524
|
+
* @param keyNodeOrEntry - The node to check.
|
|
525
|
+
* @returns True if the node is a leaf, false otherwise.
|
|
469
526
|
*/
|
|
470
527
|
isLeaf(keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined): boolean {
|
|
471
528
|
keyNodeOrEntry = this.ensureNode(keyNodeOrEntry);
|
|
472
529
|
if (keyNodeOrEntry === undefined) return false;
|
|
473
|
-
if (keyNodeOrEntry === null) return true;
|
|
530
|
+
if (keyNodeOrEntry === null) return true; // A null spot is considered a leaf
|
|
474
531
|
return !this.isRealNode(keyNodeOrEntry.left) && !this.isRealNode(keyNodeOrEntry.right);
|
|
475
532
|
}
|
|
476
533
|
|
|
477
534
|
/**
|
|
478
|
-
*
|
|
479
|
-
*
|
|
535
|
+
* Checks if the given item is a [key, value] entry pair.
|
|
536
|
+
* @remarks Time O(1), Space O(1)
|
|
480
537
|
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
|
484
|
-
* parameter in the `isEntry` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or type `R`.
|
|
485
|
-
* The function checks if the provided `keyNodeOrEntry` is of type `BTN
|
|
486
|
-
* @returns The `isEntry` function is checking if the `keyNodeOrEntry` parameter is an array
|
|
487
|
-
* with a length of 2. If it is, then it returns `true`, indicating that the parameter is of type
|
|
488
|
-
* `BTNEntry<K, V>`. If the condition is not met, it returns `false`.
|
|
538
|
+
* @param keyNodeOrEntry - The item to check.
|
|
539
|
+
* @returns True if it's an entry, false otherwise.
|
|
489
540
|
*/
|
|
490
541
|
isEntry(
|
|
491
542
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -494,15 +545,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
494
545
|
}
|
|
495
546
|
|
|
496
547
|
/**
|
|
497
|
-
*
|
|
498
|
-
*
|
|
548
|
+
* Checks if the given key is valid (comparable or null).
|
|
549
|
+
* @remarks Time O(1), Space O(1)
|
|
499
550
|
*
|
|
500
|
-
*
|
|
501
|
-
* @
|
|
502
|
-
* TypeScript.
|
|
503
|
-
* @returns The function `isValidKey` is checking if the `key` parameter is `null` or if it is comparable.
|
|
504
|
-
* If the `key` is `null`, the function returns `true`. Otherwise, it returns the result of the
|
|
505
|
-
* `isComparable` function, which is not provided in the code snippet.
|
|
551
|
+
* @param key - The key to validate.
|
|
552
|
+
* @returns True if the key is valid, false otherwise.
|
|
506
553
|
*/
|
|
507
554
|
isValidKey(key: any): key is K {
|
|
508
555
|
if (key === null) return true;
|
|
@@ -510,21 +557,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
510
557
|
}
|
|
511
558
|
|
|
512
559
|
/**
|
|
513
|
-
*
|
|
514
|
-
*
|
|
560
|
+
* Adds a new node to the tree.
|
|
561
|
+
* @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).
|
|
515
562
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* @
|
|
519
|
-
* seems to be for adding a new node to a binary tree structure. The `keyNodeOrEntry`
|
|
520
|
-
* parameter in the method can accept different types of values:
|
|
521
|
-
* @param {V} [value] - The `value` parameter in the `add` method represents the value associated
|
|
522
|
-
* with the key that you want to add to the binary tree. When adding a key-value pair to the binary
|
|
523
|
-
* tree, you provide the key and its corresponding value. The `add` method then creates a new node
|
|
524
|
-
* with this
|
|
525
|
-
* @returns The `add` method returns a boolean value. It returns `true` if the insertion of the new
|
|
526
|
-
* node was successful, and `false` if the insertion position could not be found or if a duplicate
|
|
527
|
-
* key was found and the node was replaced instead of inserted.
|
|
563
|
+
* @param keyNodeOrEntry - The key, node, or entry to add.
|
|
564
|
+
* @param [value] - The value, if providing just a key.
|
|
565
|
+
* @returns True if the addition was successful, false otherwise.
|
|
528
566
|
*/
|
|
529
567
|
add(
|
|
530
568
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -533,7 +571,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
533
571
|
const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
|
534
572
|
if (newNode === undefined) return false;
|
|
535
573
|
|
|
536
|
-
// If the tree is empty, directly set the new node as the root node
|
|
537
574
|
if (!this._root) {
|
|
538
575
|
this._setRoot(newNode);
|
|
539
576
|
if (this._isMapMode) this._setValue(newNode?.key, newValue);
|
|
@@ -542,28 +579,24 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
542
579
|
}
|
|
543
580
|
|
|
544
581
|
const queue = new Queue<BinaryTreeNode<K, V>>([this._root]);
|
|
545
|
-
let potentialParent: BinaryTreeNode<K, V> | undefined;
|
|
546
|
-
|
|
582
|
+
let potentialParent: BinaryTreeNode<K, V> | undefined;
|
|
547
583
|
while (queue.length > 0) {
|
|
548
584
|
const cur = queue.shift();
|
|
549
585
|
|
|
550
586
|
if (!cur) continue;
|
|
551
587
|
|
|
552
588
|
if (!this._isDuplicate) {
|
|
553
|
-
// Check for duplicate keys when newNode is not null
|
|
554
589
|
if (newNode !== null && cur.key === newNode.key) {
|
|
555
590
|
this._replaceNode(cur, newNode);
|
|
556
591
|
if (this._isMapMode) this._setValue(cur.key, newValue);
|
|
557
|
-
return true; //
|
|
592
|
+
return true; // Replaced existing node
|
|
558
593
|
}
|
|
559
594
|
}
|
|
560
595
|
|
|
561
|
-
// Record the first possible insertion location found
|
|
562
596
|
if (potentialParent === undefined && (cur.left === undefined || cur.right === undefined)) {
|
|
563
597
|
potentialParent = cur;
|
|
564
598
|
}
|
|
565
599
|
|
|
566
|
-
// Continue traversing the left and right subtrees
|
|
567
600
|
if (cur.left !== null) {
|
|
568
601
|
if (cur.left) queue.push(cur.left);
|
|
569
602
|
}
|
|
@@ -572,7 +605,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
572
605
|
}
|
|
573
606
|
}
|
|
574
607
|
|
|
575
|
-
// At the end of the traversal, if the insertion position is found, insert
|
|
576
608
|
if (potentialParent) {
|
|
577
609
|
if (potentialParent.left === undefined) {
|
|
578
610
|
potentialParent.left = newNode;
|
|
@@ -584,26 +616,16 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
584
616
|
return true;
|
|
585
617
|
}
|
|
586
618
|
|
|
587
|
-
return false; //
|
|
619
|
+
return false; // Should not happen if tree is not full?
|
|
588
620
|
}
|
|
589
621
|
|
|
590
622
|
/**
|
|
591
|
-
*
|
|
592
|
-
* Space
|
|
623
|
+
* Adds multiple items to the tree.
|
|
624
|
+
* @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).
|
|
593
625
|
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
* each
|
|
597
|
-
* @param keysNodesEntriesOrRaws - `keysNodesEntriesOrRaws` is an iterable that can contain a
|
|
598
|
-
* mix of keys, nodes, entries, or raw values. Each element in this iterable can be of type
|
|
599
|
-
* `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
|
|
600
|
-
* @param [values] - The `values` parameter in the `addMany` function is an optional parameter that
|
|
601
|
-
* accepts an iterable of values. These values correspond to the keys or nodes being added in the
|
|
602
|
-
* `keysNodesEntriesOrRaws` parameter. If provided, the function will iterate over the values and
|
|
603
|
-
* assign them
|
|
604
|
-
* @returns The `addMany` method returns an array of boolean values indicating whether each key,
|
|
605
|
-
* node, entry, or raw value was successfully added to the data structure. Each boolean value
|
|
606
|
-
* corresponds to the success of adding the corresponding key or value in the input iterable.
|
|
626
|
+
* @param keysNodesEntriesOrRaws - An iterable of items to add.
|
|
627
|
+
* @param [values] - An optional parallel iterable of values.
|
|
628
|
+
* @returns An array of booleans indicating the success of each individual `add` operation.
|
|
607
629
|
*/
|
|
608
630
|
addMany(
|
|
609
631
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -611,7 +633,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
611
633
|
>,
|
|
612
634
|
values?: Iterable<V | undefined>
|
|
613
635
|
): boolean[] {
|
|
614
|
-
// TODO not sure addMany not be run multi times
|
|
615
636
|
const inserted: boolean[] = [];
|
|
616
637
|
|
|
617
638
|
let valuesIterator: Iterator<V | undefined> | undefined;
|
|
@@ -636,28 +657,21 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
636
657
|
}
|
|
637
658
|
|
|
638
659
|
/**
|
|
639
|
-
*
|
|
640
|
-
*
|
|
660
|
+
* Merges another tree into this one by adding all its nodes.
|
|
661
|
+
* @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`).
|
|
641
662
|
*
|
|
642
|
-
*
|
|
643
|
-
* elements from the other tree.
|
|
644
|
-
* @param anotherTree - BinaryTree<K, V, R, MK, MV, MR>
|
|
663
|
+
* @param anotherTree - The tree to merge.
|
|
645
664
|
*/
|
|
646
|
-
merge(anotherTree: BinaryTree<K, V, R
|
|
665
|
+
merge(anotherTree: BinaryTree<K, V, R>) {
|
|
647
666
|
this.addMany(anotherTree, []);
|
|
648
667
|
}
|
|
649
668
|
|
|
650
669
|
/**
|
|
651
|
-
*
|
|
652
|
-
*
|
|
670
|
+
* Clears the tree and refills it with new items.
|
|
671
|
+
* @remarks Time O(N) (for `clear`) + O(N * M) (for `addMany`) = O(N * M). Space O(M) (from `addMany`).
|
|
653
672
|
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the `refill`
|
|
657
|
-
* method can accept an iterable containing a mix of `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` objects or `R`
|
|
658
|
-
* objects.
|
|
659
|
-
* @param [values] - The `values` parameter in the `refill` method is an optional parameter that
|
|
660
|
-
* accepts an iterable of values of type `V` or `undefined`.
|
|
673
|
+
* @param keysNodesEntriesOrRaws - An iterable of items to add.
|
|
674
|
+
* @param [values] - An optional parallel iterable of values.
|
|
661
675
|
*/
|
|
662
676
|
refill(
|
|
663
677
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -670,19 +684,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
670
684
|
}
|
|
671
685
|
|
|
672
686
|
/**
|
|
673
|
-
*
|
|
674
|
-
*
|
|
687
|
+
* Deletes a node from the tree.
|
|
688
|
+
* @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).
|
|
675
689
|
*
|
|
676
|
-
*
|
|
677
|
-
*
|
|
678
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry
|
|
679
|
-
* - The `delete` method you provided is used to delete a node from a binary tree based on the key,
|
|
680
|
-
* node, entry or raw data. The method returns an array of
|
|
681
|
-
* `BinaryTreeDeleteResult` objects containing information about the deleted node and whether
|
|
682
|
-
* balancing is needed.
|
|
683
|
-
* @returns The `delete` method returns an array of `BinaryTreeDeleteResult` objects. Each object in
|
|
684
|
-
* the array contains information about the node that was deleted (`deleted`) and the node that may
|
|
685
|
-
* need to be balanced (`needBalanced`).
|
|
690
|
+
* @param keyNodeOrEntry - The node to delete.
|
|
691
|
+
* @returns An array containing deletion results (for compatibility with self-balancing trees).
|
|
686
692
|
*/
|
|
687
693
|
delete(
|
|
688
694
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -698,13 +704,19 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
698
704
|
let orgCurrent: BinaryTreeNode<K, V> | undefined = curr;
|
|
699
705
|
|
|
700
706
|
if (!curr.left && !curr.right && !parent) {
|
|
707
|
+
// Deleting the root with no children
|
|
701
708
|
this._setRoot(undefined);
|
|
702
709
|
} else if (curr.left) {
|
|
710
|
+
// Node has a left child (or two children)
|
|
711
|
+
// Find the rightmost node in the left subtree
|
|
703
712
|
const leftSubTreeRightMost = this.getRightMost(node => node, curr.left);
|
|
704
713
|
if (leftSubTreeRightMost) {
|
|
705
714
|
const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
|
|
715
|
+
// Swap properties
|
|
706
716
|
orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
|
|
717
|
+
// `orgCurrent` is now the node to be physically deleted (which was the rightmost)
|
|
707
718
|
if (parentOfLeftSubTreeMax) {
|
|
719
|
+
// Unlink the rightmost node
|
|
708
720
|
if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
|
|
709
721
|
parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
|
|
710
722
|
else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left;
|
|
@@ -712,6 +724,8 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
712
724
|
}
|
|
713
725
|
}
|
|
714
726
|
} else if (parent) {
|
|
727
|
+
// Node has no left child, but has a parent
|
|
728
|
+
// Promote the right child (which could be null)
|
|
715
729
|
const { familyPosition: fp } = curr;
|
|
716
730
|
if (fp === 'LEFT' || fp === 'ROOT_LEFT') {
|
|
717
731
|
parent.left = curr.right;
|
|
@@ -720,6 +734,8 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
720
734
|
}
|
|
721
735
|
needBalanced = parent;
|
|
722
736
|
} else {
|
|
737
|
+
// Deleting the root, which has no left child
|
|
738
|
+
// Promote the right child as the new root
|
|
723
739
|
this._setRoot(curr.right);
|
|
724
740
|
curr.right = undefined;
|
|
725
741
|
}
|
|
@@ -732,28 +748,16 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
732
748
|
}
|
|
733
749
|
|
|
734
750
|
/**
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
* @param
|
|
741
|
-
*
|
|
742
|
-
* @param [
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
* @param {C} callback - The `callback` parameter in the `search` function is a callback function
|
|
746
|
-
* that will be called on each node that matches the search criteria. It is of type `C`, which
|
|
747
|
-
* extends `NodeCallback<BinaryTreeNode<K, V> | null>`. The default value for `callback` is `this._DEFAULT_NODE_CALLBACK` if
|
|
748
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `search` function is
|
|
749
|
-
* used to specify the node from which the search operation should begin. It represents the starting
|
|
750
|
-
* point in the binary tree where the search will be performed. If no specific `startNode` is
|
|
751
|
-
* provided, the search operation will start from the root
|
|
752
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `search` function
|
|
753
|
-
* specifies the type of iteration to be used when searching for nodes in a binary tree. It can have
|
|
754
|
-
* two possible values:
|
|
755
|
-
* @returns The `search` function returns an array of values that match the provided criteria based
|
|
756
|
-
* on the search algorithm implemented within the function.
|
|
751
|
+
* Searches the tree for nodes matching a predicate.
|
|
752
|
+
* @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).
|
|
753
|
+
*
|
|
754
|
+
* @template C - The type of the callback function.
|
|
755
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
756
|
+
* @param [onlyOne=false] - If true, stops after finding the first match.
|
|
757
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
|
|
758
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
759
|
+
* @param [iterationType=this.iterationType] - Whether to use 'RECURSIVE' or 'ITERATIVE' search.
|
|
760
|
+
* @returns An array of results from the callback function for each matching node.
|
|
757
761
|
*/
|
|
758
762
|
search<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
759
763
|
keyNodeEntryOrPredicate:
|
|
@@ -790,6 +794,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
790
794
|
dfs(startNode);
|
|
791
795
|
} else {
|
|
792
796
|
const stack = [startNode];
|
|
797
|
+
|
|
793
798
|
while (stack.length > 0) {
|
|
794
799
|
const cur = stack.pop();
|
|
795
800
|
if (this.isRealNode(cur)) {
|
|
@@ -806,6 +811,16 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
806
811
|
return ans;
|
|
807
812
|
}
|
|
808
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Gets all nodes matching a predicate.
|
|
816
|
+
* @remarks Time O(N) (via `search`). Space O(H) or O(N) (via `search`).
|
|
817
|
+
*
|
|
818
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
819
|
+
* @param [onlyOne=false] - If true, stops after finding the first match.
|
|
820
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
821
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
822
|
+
* @returns An array of matching nodes.
|
|
823
|
+
*/
|
|
809
824
|
getNodes(
|
|
810
825
|
keyNodeEntryOrPredicate:
|
|
811
826
|
| K
|
|
@@ -819,27 +834,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
819
834
|
iterationType?: IterationType
|
|
820
835
|
): BinaryTreeNode<K, V>[];
|
|
821
836
|
|
|
822
|
-
/**
|
|
823
|
-
* Time Complexity: O(n)
|
|
824
|
-
* Space Complexity: O(k + log n)
|
|
825
|
-
*
|
|
826
|
-
* The function `getNodes` retrieves nodes from a binary tree based on a key, node, entry, raw data,
|
|
827
|
-
* or predicate, with options for recursive or iterative traversal.
|
|
828
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
|
|
829
|
-
* - The `getNodes` function you provided takes several parameters:
|
|
830
|
-
* @param [onlyOne=false] - The `onlyOne` parameter in the `getNodes` function is a boolean flag that
|
|
831
|
-
* determines whether to return only the first node that matches the criteria specified by the
|
|
832
|
-
* `keyNodeEntryOrPredicate` parameter. If `onlyOne` is set to `true`, the function will
|
|
833
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
834
|
-
* `getNodes` function is used to specify the starting point for traversing the binary tree. It
|
|
835
|
-
* represents the root node of the binary tree or the node from which the traversal should begin. If
|
|
836
|
-
* not provided, the default value is set to `this._root
|
|
837
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNodes` function
|
|
838
|
-
* determines the type of iteration to be performed when traversing the nodes of a binary tree. It
|
|
839
|
-
* can have two possible values:
|
|
840
|
-
* @returns The `getNodes` function returns an array of nodes that satisfy the provided condition
|
|
841
|
-
* based on the input parameters and the iteration type specified.
|
|
842
|
-
*/
|
|
843
837
|
getNodes(
|
|
844
838
|
keyNodeEntryOrPredicate:
|
|
845
839
|
| K
|
|
@@ -856,24 +850,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
856
850
|
}
|
|
857
851
|
|
|
858
852
|
/**
|
|
859
|
-
*
|
|
860
|
-
*
|
|
853
|
+
* Gets the first node matching a predicate.
|
|
854
|
+
* @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`).
|
|
861
855
|
*
|
|
862
|
-
*
|
|
863
|
-
*
|
|
864
|
-
* @param
|
|
865
|
-
*
|
|
866
|
-
* node, entry, raw data, or a predicate function.
|
|
867
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
868
|
-
* `getNode` function is used to specify the starting point for searching for a node in a binary
|
|
869
|
-
* tree. If no specific starting point is provided, the default value is set to `this._root`, which
|
|
870
|
-
* is typically the root node of the binary tree.
|
|
871
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is
|
|
872
|
-
* used to specify the type of iteration to be performed when searching for a node. It has a default
|
|
873
|
-
* value of `this.iterationType`, which means it will use the iteration type defined in the current
|
|
874
|
-
* context if no specific value is provided
|
|
875
|
-
* @returns The `getNode` function is returning the first node that matches the specified criteria,
|
|
876
|
-
* or `null` if no matching node is found.
|
|
856
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
857
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
858
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
859
|
+
* @returns The first matching node, or undefined if not found.
|
|
877
860
|
*/
|
|
878
861
|
getNode(
|
|
879
862
|
keyNodeEntryOrPredicate:
|
|
@@ -890,26 +873,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
890
873
|
}
|
|
891
874
|
|
|
892
875
|
/**
|
|
893
|
-
*
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
* node
|
|
898
|
-
* @param
|
|
899
|
-
*
|
|
900
|
-
* following types:
|
|
901
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `get`
|
|
902
|
-
* method is used to specify the starting point for searching for a key or node in the binary tree.
|
|
903
|
-
* If no specific starting point is provided, the default starting point is the root of the binary
|
|
904
|
-
* tree (`this._root`).
|
|
905
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `get` method is used
|
|
906
|
-
* to specify the type of iteration to be performed when searching for a key in the binary tree. It
|
|
907
|
-
* is an optional parameter with a default value of `this.iterationType`, which means it will use the
|
|
908
|
-
* iteration type defined in the
|
|
909
|
-
* @returns The `get` method is returning the value associated with the specified key, node, entry,
|
|
910
|
-
* raw data, or predicate in the binary tree map. If the specified key or node is found in the tree,
|
|
911
|
-
* the method returns the corresponding value. If the key or node is not found, it returns
|
|
912
|
-
* `undefined`.
|
|
876
|
+
* Gets the value associated with a key.
|
|
877
|
+
* @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.
|
|
878
|
+
*
|
|
879
|
+
* @param keyNodeEntryOrPredicate - The key, node, or entry to get the value for.
|
|
880
|
+
* @param [startNode=this._root] - The node to start searching from (if not in Map mode).
|
|
881
|
+
* @param [iterationType=this.iterationType] - The traversal method (if not in Map mode).
|
|
882
|
+
* @returns The associated value, or undefined.
|
|
913
883
|
*/
|
|
914
884
|
override get(
|
|
915
885
|
keyNodeEntryOrPredicate: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -924,6 +894,15 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
924
894
|
return this.getNode(keyNodeEntryOrPredicate, startNode, iterationType)?.value;
|
|
925
895
|
}
|
|
926
896
|
|
|
897
|
+
/**
|
|
898
|
+
* Checks if a node matching the predicate exists in the tree.
|
|
899
|
+
* @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`).
|
|
900
|
+
*
|
|
901
|
+
* @param [keyNodeEntryOrPredicate] - The key, node, entry, or predicate to check for.
|
|
902
|
+
* @param [startNode] - The node to start the search from.
|
|
903
|
+
* @param [iterationType] - The traversal method.
|
|
904
|
+
* @returns True if a matching node exists, false otherwise.
|
|
905
|
+
*/
|
|
927
906
|
override has(
|
|
928
907
|
keyNodeEntryOrPredicate?:
|
|
929
908
|
| K
|
|
@@ -936,27 +915,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
936
915
|
iterationType?: IterationType
|
|
937
916
|
): boolean;
|
|
938
917
|
|
|
939
|
-
/**
|
|
940
|
-
* Time Complexity: O(n)
|
|
941
|
-
* Space Complexity: O(log n)
|
|
942
|
-
*
|
|
943
|
-
* The `has` function in TypeScript checks if a specified key, node, entry, raw data, or predicate
|
|
944
|
-
* exists in the data structure.
|
|
945
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
|
|
946
|
-
* - The `keyNodeEntryOrPredicate` parameter in the `override has` method can accept one of
|
|
947
|
-
* the following types:
|
|
948
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
949
|
-
* `override` method is used to specify the starting point for the search operation within the data
|
|
950
|
-
* structure. It defaults to `this._root` if not provided explicitly.
|
|
951
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `override has` method
|
|
952
|
-
* is used to specify the type of iteration to be performed. It has a default value of
|
|
953
|
-
* `this.iterationType`, which means it will use the iteration type defined in the current context if
|
|
954
|
-
* no value is provided when calling the method.
|
|
955
|
-
* @returns The `override has` method is returning a boolean value. It checks if there are any nodes
|
|
956
|
-
* that match the provided key, node, entry, raw data, or predicate in the tree structure. If there
|
|
957
|
-
* are matching nodes, it returns `true`, indicating that the tree contains the specified element.
|
|
958
|
-
* Otherwise, it returns `false`.
|
|
959
|
-
*/
|
|
960
918
|
override has(
|
|
961
919
|
keyNodeEntryOrPredicate:
|
|
962
920
|
| K
|
|
@@ -972,10 +930,8 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
972
930
|
}
|
|
973
931
|
|
|
974
932
|
/**
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
*
|
|
978
|
-
* The clear function removes nodes and values in map mode.
|
|
933
|
+
* Clears the tree of all nodes and values.
|
|
934
|
+
* @remarks Time O(N) if in Map mode (due to `_store.clear()`), O(1) otherwise. Space O(1)
|
|
979
935
|
*/
|
|
980
936
|
clear() {
|
|
981
937
|
this._clearNodes();
|
|
@@ -983,32 +939,21 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
983
939
|
}
|
|
984
940
|
|
|
985
941
|
/**
|
|
986
|
-
*
|
|
987
|
-
*
|
|
942
|
+
* Checks if the tree is empty.
|
|
943
|
+
* @remarks Time O(1), Space O(1)
|
|
988
944
|
*
|
|
989
|
-
*
|
|
990
|
-
* boolean value.
|
|
991
|
-
* @returns The `isEmpty()` method is returning a boolean value, specifically `true` if the `_size`
|
|
992
|
-
* property is equal to 0, indicating that the data structure is empty, and `false` otherwise.
|
|
945
|
+
* @returns True if the tree has no nodes, false otherwise.
|
|
993
946
|
*/
|
|
994
947
|
isEmpty(): boolean {
|
|
995
948
|
return this._size === 0;
|
|
996
949
|
}
|
|
997
950
|
|
|
998
951
|
/**
|
|
999
|
-
*
|
|
1000
|
-
* Space
|
|
952
|
+
* Checks if the tree is perfectly balanced.
|
|
953
|
+
* @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).
|
|
1001
954
|
*
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1004
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
|
1005
|
-
* point for checking if the binary tree is perfectly balanced. It represents the root node of the
|
|
1006
|
-
* binary tree or a specific node from which the balance check should begin.
|
|
1007
|
-
* @returns The method `isPerfectlyBalanced` is returning a boolean value, which indicates whether
|
|
1008
|
-
* the tree starting from the `startNode` node is perfectly balanced or not. The return value is
|
|
1009
|
-
* determined by comparing the minimum height of the tree with the height of the tree. If the minimum
|
|
1010
|
-
* height plus 1 is greater than or equal to the height of the tree, then it is considered perfectly
|
|
1011
|
-
* balanced and
|
|
955
|
+
* @param [startNode=this._root] - The node to start checking from.
|
|
956
|
+
* @returns True if perfectly balanced, false otherwise.
|
|
1012
957
|
*/
|
|
1013
958
|
isPerfectlyBalanced(
|
|
1014
959
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root
|
|
@@ -1017,30 +962,19 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1017
962
|
}
|
|
1018
963
|
|
|
1019
964
|
/**
|
|
1020
|
-
*
|
|
1021
|
-
* Space
|
|
965
|
+
* Checks if the tree is a valid Binary Search Tree (BST).
|
|
966
|
+
* @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).
|
|
1022
967
|
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
* @
|
|
1026
|
-
* function represents the starting point for checking whether a binary search tree (BST) is valid.
|
|
1027
|
-
* It can be a node in the BST or a reference to the root of the BST. If no specific node is
|
|
1028
|
-
* provided, the function will default to
|
|
1029
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `isBST` function
|
|
1030
|
-
* determines whether the function should use a recursive approach or an iterative approach to check
|
|
1031
|
-
* if the binary search tree (BST) is valid.
|
|
1032
|
-
* @returns The `isBST` method is returning a boolean value, which indicates whether the binary
|
|
1033
|
-
* search tree (BST) represented by the given root node is a valid BST or not. The method checks if
|
|
1034
|
-
* the tree satisfies the BST property, where for every node, all nodes in its left subtree have keys
|
|
1035
|
-
* less than the node's key, and all nodes in its right subtree have keys greater than the node's
|
|
968
|
+
* @param [startNode=this._root] - The node to start checking from.
|
|
969
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
970
|
+
* @returns True if it's a valid BST, false otherwise.
|
|
1036
971
|
*/
|
|
1037
972
|
isBST(
|
|
1038
973
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
1039
974
|
iterationType: IterationType = this.iterationType
|
|
1040
975
|
): boolean {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
if (!startNode) return true;
|
|
976
|
+
const startNodeSired = this.ensureNode(startNode);
|
|
977
|
+
if (!startNodeSired) return true;
|
|
1044
978
|
|
|
1045
979
|
if (iterationType === 'RECURSIVE') {
|
|
1046
980
|
const dfs = (cur: BinaryTreeNode<K, V> | null | undefined, min: number, max: number): boolean => {
|
|
@@ -1050,15 +984,15 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1050
984
|
return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
|
|
1051
985
|
};
|
|
1052
986
|
|
|
1053
|
-
const isStandardBST = dfs(
|
|
1054
|
-
const isInverseBST = dfs(
|
|
987
|
+
const isStandardBST = dfs(startNodeSired, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
|
|
988
|
+
const isInverseBST = dfs(startNodeSired, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER); // Check for reverse BST
|
|
1055
989
|
return isStandardBST || isInverseBST;
|
|
1056
990
|
} else {
|
|
991
|
+
// Iterative in-order traversal check
|
|
1057
992
|
const checkBST = (checkMax = false) => {
|
|
1058
|
-
const stack = [];
|
|
993
|
+
const stack: BinaryTreeNode<K, V>[] = [];
|
|
1059
994
|
let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
|
|
1060
|
-
|
|
1061
|
-
let curr: BinaryTreeNode<K, V> | null | undefined = startNode;
|
|
995
|
+
let curr: BinaryTreeNode<K, V> | null | undefined = startNodeSired;
|
|
1062
996
|
while (this.isRealNode(curr) || stack.length > 0) {
|
|
1063
997
|
while (this.isRealNode(curr)) {
|
|
1064
998
|
stack.push(curr);
|
|
@@ -1072,27 +1006,19 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1072
1006
|
}
|
|
1073
1007
|
return true;
|
|
1074
1008
|
};
|
|
1075
|
-
const isStandardBST = checkBST(false)
|
|
1076
|
-
|
|
1009
|
+
const isStandardBST = checkBST(false);
|
|
1010
|
+
const isInverseBST = checkBST(true);
|
|
1077
1011
|
return isStandardBST || isInverseBST;
|
|
1078
1012
|
}
|
|
1079
1013
|
}
|
|
1080
1014
|
|
|
1081
1015
|
/**
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1016
|
+
* Gets the depth of a node (distance from `startNode`).
|
|
1017
|
+
* @remarks Time O(H), where H is the depth of the `dist` node relative to `startNode`. O(N) worst-case. Space O(1).
|
|
1084
1018
|
*
|
|
1085
|
-
* The
|
|
1086
|
-
* @param
|
|
1087
|
-
*
|
|
1088
|
-
* It is the target node for which you want to calculate the depth from the `startNode` node.
|
|
1089
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1090
|
-
* `getDepth` function represents the starting point from which you want to calculate the depth of a
|
|
1091
|
-
* given node or entry in a binary tree. If no specific starting point is provided, the default value
|
|
1092
|
-
* for `startNode` is set to the root of the binary
|
|
1093
|
-
* @returns The `getDepth` method returns the depth of a given node `dist` relative to the
|
|
1094
|
-
* `startNode` node in a binary tree. If the `dist` node is not found in the path to the `startNode`
|
|
1095
|
-
* node, it returns the depth of the `dist` node from the root of the tree.
|
|
1019
|
+
* @param dist - The node to find the depth of.
|
|
1020
|
+
* @param [startNode=this._root] - The node to measure depth from (defaults to root).
|
|
1021
|
+
* @returns The depth (0 if `dist` is `startNode`).
|
|
1096
1022
|
*/
|
|
1097
1023
|
getDepth(
|
|
1098
1024
|
dist: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -1112,21 +1038,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1112
1038
|
}
|
|
1113
1039
|
|
|
1114
1040
|
/**
|
|
1115
|
-
*
|
|
1116
|
-
* Space
|
|
1041
|
+
* Gets the maximum height of the tree (longest path from startNode to a leaf).
|
|
1042
|
+
* @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).
|
|
1117
1043
|
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
* @
|
|
1121
|
-
* point from which the height of the binary tree will be calculated. It can be a node in the binary
|
|
1122
|
-
* tree or a reference to the root of the tree. If not provided, it defaults to the root of the
|
|
1123
|
-
* binary tree data structure.
|
|
1124
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is used to determine the type
|
|
1125
|
-
* of iteration to be performed while calculating the height of the binary tree. It can have two
|
|
1126
|
-
* possible values:
|
|
1127
|
-
* @returns The `getHeight` method returns the height of the binary tree starting from the specified
|
|
1128
|
-
* root node. The height is calculated based on the maximum depth of the tree, considering either a
|
|
1129
|
-
* recursive approach or an iterative approach depending on the `iterationType` parameter.
|
|
1044
|
+
* @param [startNode=this._root] - The node to start measuring from.
|
|
1045
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1046
|
+
* @returns The height ( -1 for an empty tree, 0 for a single-node tree).
|
|
1130
1047
|
*/
|
|
1131
1048
|
getHeight(
|
|
1132
1049
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1145,6 +1062,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1145
1062
|
|
|
1146
1063
|
return _getMaxHeight(startNode);
|
|
1147
1064
|
} else {
|
|
1065
|
+
// Iterative (using DFS)
|
|
1148
1066
|
const stack: { node: BinaryTreeNode<K, V>; depth: number }[] = [{ node: startNode, depth: 0 }];
|
|
1149
1067
|
let maxHeight = 0;
|
|
1150
1068
|
|
|
@@ -1162,22 +1080,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1162
1080
|
}
|
|
1163
1081
|
|
|
1164
1082
|
/**
|
|
1165
|
-
*
|
|
1166
|
-
* Space
|
|
1083
|
+
* Gets the minimum height of the tree (shortest path from startNode to a leaf).
|
|
1084
|
+
* @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).
|
|
1167
1085
|
*
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
* @
|
|
1171
|
-
* `getMinHeight` function represents the starting node from which the minimum height of the binary
|
|
1172
|
-
* tree will be calculated. It is either a node in the binary tree or a reference to the root of the
|
|
1173
|
-
* tree. If not provided, the default value is the root
|
|
1174
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getMinHeight` method
|
|
1175
|
-
* specifies the type of iteration to use when calculating the minimum height of a binary tree. It
|
|
1176
|
-
* can have two possible values:
|
|
1177
|
-
* @returns The `getMinHeight` method returns the minimum height of the binary tree starting from the
|
|
1178
|
-
* specified root node. The height is calculated based on the shortest path from the root node to a
|
|
1179
|
-
* leaf node in the tree. The method uses either a recursive approach or an iterative approach (using
|
|
1180
|
-
* a stack) based on the `iterationType` parameter.
|
|
1086
|
+
* @param [startNode=this._root] - The node to start measuring from.
|
|
1087
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1088
|
+
* @returns The minimum height (-1 for empty, 0 for single node).
|
|
1181
1089
|
*/
|
|
1182
1090
|
getMinHeight(
|
|
1183
1091
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1189,7 +1097,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1189
1097
|
if (iterationType === 'RECURSIVE') {
|
|
1190
1098
|
const _getMinHeight = (cur: BinaryTreeNode<K, V> | null | undefined): number => {
|
|
1191
1099
|
if (!this.isRealNode(cur)) return 0;
|
|
1192
|
-
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return 0;
|
|
1100
|
+
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return 0; // Leaf node
|
|
1193
1101
|
const leftMinHeight = _getMinHeight(cur.left);
|
|
1194
1102
|
const rightMinHeight = _getMinHeight(cur.right);
|
|
1195
1103
|
return Math.min(leftMinHeight, rightMinHeight) + 1;
|
|
@@ -1197,6 +1105,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1197
1105
|
|
|
1198
1106
|
return _getMinHeight(startNode);
|
|
1199
1107
|
} else {
|
|
1108
|
+
// Iterative (using post-order DFS)
|
|
1200
1109
|
const stack: BinaryTreeNode<K, V>[] = [];
|
|
1201
1110
|
let node: BinaryTreeNode<K, V> | null | undefined = startNode,
|
|
1202
1111
|
last: BinaryTreeNode<K, V> | null | undefined = null;
|
|
@@ -1226,26 +1135,16 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1226
1135
|
}
|
|
1227
1136
|
|
|
1228
1137
|
/**
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1138
|
+
* Gets the path from a given node up to the root.
|
|
1139
|
+
* @remarks Time O(H), where H is the depth of the `beginNode`. O(N) worst-case. Space O(H) for the result array.
|
|
1231
1140
|
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
* @param
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
* type `C
|
|
1238
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } beginNode - The `beginNode` parameter in the
|
|
1239
|
-
* `getPathToRoot` function can be either a key, a node, an entry, or any other value of type `R`.
|
|
1240
|
-
* @param [isReverse=true] - The `isReverse` parameter in the `getPathToRoot` function determines
|
|
1241
|
-
* whether the resulting path from the given `beginNode` to the root should be in reverse order or
|
|
1242
|
-
* not. If `isReverse` is set to `true`, the path will be reversed before being returned. If `is
|
|
1243
|
-
* @returns The function `getPathToRoot` returns an array of the return values of the callback
|
|
1244
|
-
* function `callback` applied to each node in the path from the `beginNode` to the root node. The
|
|
1245
|
-
* array is either in reverse order or in the original order based on the value of the `isReverse`
|
|
1246
|
-
* parameter.
|
|
1141
|
+
* @template C - The type of the callback function.
|
|
1142
|
+
* @param beginNode - The node to start the path from.
|
|
1143
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on each node in the path.
|
|
1144
|
+
* @param [isReverse=false] - If true, returns the path from root-to-node.
|
|
1145
|
+
* @returns An array of callback results.
|
|
1247
1146
|
*/
|
|
1248
|
-
getPathToRoot<C extends NodeCallback<
|
|
1147
|
+
getPathToRoot<C extends NodeCallback<BinaryTreeNode<K, V> | undefined>>(
|
|
1249
1148
|
beginNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
1250
1149
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1251
1150
|
isReverse = false
|
|
@@ -1256,36 +1155,24 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1256
1155
|
if (!beginNodeEnsured) return result;
|
|
1257
1156
|
|
|
1258
1157
|
while (beginNodeEnsured.parent) {
|
|
1259
|
-
// Array.push + Array.reverse is more efficient than Array.unshift
|
|
1260
1158
|
result.push(callback(beginNodeEnsured));
|
|
1261
1159
|
beginNodeEnsured = beginNodeEnsured.parent;
|
|
1262
1160
|
}
|
|
1263
|
-
result.push(callback(beginNodeEnsured));
|
|
1161
|
+
result.push(callback(beginNodeEnsured)); // Add the root
|
|
1264
1162
|
return isReverse ? result.reverse() : result;
|
|
1265
1163
|
}
|
|
1266
1164
|
|
|
1267
1165
|
/**
|
|
1268
|
-
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
* @param
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
* tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
|
|
1279
|
-
* starting point is provided, the function will default
|
|
1280
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getLeftMost` function
|
|
1281
|
-
* specifies the type of iteration to be used when traversing the binary tree nodes. It can have two
|
|
1282
|
-
* possible values:
|
|
1283
|
-
* @returns The `getLeftMost` function returns the result of the callback function `C` applied to the
|
|
1284
|
-
* leftmost node in the binary tree starting from the `startNode` node. If the `startNode` node is
|
|
1285
|
-
* `NIL`, it returns the result of the callback function applied to `undefined`. If the `startNode`
|
|
1286
|
-
* node is not a real node, it returns the result of the callback
|
|
1287
|
-
*/
|
|
1288
|
-
getLeftMost<C extends NodeCallback<OptNodeOrNull<BinaryTreeNode<K, V>>>>(
|
|
1166
|
+
* Finds the leftmost node in a subtree (the node with the smallest key in a BST).
|
|
1167
|
+
* @remarks Time O(H), where H is the height of the left spine. O(N) worst-case. Space O(H) for recursive/trampoline stack.
|
|
1168
|
+
*
|
|
1169
|
+
* @template C - The type of the callback function.
|
|
1170
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on the leftmost node.
|
|
1171
|
+
* @param [startNode=this._root] - The subtree root to search from.
|
|
1172
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1173
|
+
* @returns The callback result for the leftmost node.
|
|
1174
|
+
*/
|
|
1175
|
+
getLeftMost<C extends NodeCallback<BinaryTreeNode<K, V> | undefined>>(
|
|
1289
1176
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1290
1177
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
1291
1178
|
iterationType: IterationType = this.iterationType
|
|
@@ -1293,20 +1180,21 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1293
1180
|
if (this.isNIL(startNode)) return callback(undefined);
|
|
1294
1181
|
startNode = this.ensureNode(startNode);
|
|
1295
1182
|
|
|
1296
|
-
if (!this.isRealNode(startNode)) return callback(
|
|
1297
|
-
|
|
1183
|
+
if (!this.isRealNode(startNode)) return callback(undefined);
|
|
1298
1184
|
if (iterationType === 'RECURSIVE') {
|
|
1299
1185
|
const dfs = (cur: BinaryTreeNode<K, V>): BinaryTreeNode<K, V> => {
|
|
1300
|
-
|
|
1301
|
-
|
|
1186
|
+
const { left } = cur;
|
|
1187
|
+
if (!this.isRealNode(left)) return cur;
|
|
1188
|
+
return dfs(left);
|
|
1302
1189
|
};
|
|
1303
1190
|
|
|
1304
1191
|
return callback(dfs(startNode));
|
|
1305
1192
|
} else {
|
|
1306
|
-
//
|
|
1307
|
-
const dfs =
|
|
1308
|
-
|
|
1309
|
-
|
|
1193
|
+
// Iterative (trampolined to prevent stack overflow, though 'ITERATIVE' usually means a loop)
|
|
1194
|
+
const dfs = makeTrampoline((cur: BinaryTreeNode<K, V>): Trampoline<BinaryTreeNode<K, V>> => {
|
|
1195
|
+
const { left } = cur;
|
|
1196
|
+
if (!this.isRealNode(left)) return cur;
|
|
1197
|
+
return makeTrampolineThunk(() => dfs(left));
|
|
1310
1198
|
});
|
|
1311
1199
|
|
|
1312
1200
|
return callback(dfs(startNode));
|
|
@@ -1314,48 +1202,37 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1314
1202
|
}
|
|
1315
1203
|
|
|
1316
1204
|
/**
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1321
|
-
*
|
|
1322
|
-
* @param
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
* `getRightMost` function represents the starting point for finding the rightmost node in a binary
|
|
1328
|
-
* tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
|
|
1329
|
-
* starting point is provided, the function will default
|
|
1330
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getRightMost`
|
|
1331
|
-
* function specifies the type of iteration to be used when traversing the binary tree nodes. It can
|
|
1332
|
-
* have two possible values:
|
|
1333
|
-
* @returns The `getRightMost` function returns the result of the callback function `C`, which is
|
|
1334
|
-
* passed as a parameter to the function. The callback function is called with the rightmost node in
|
|
1335
|
-
* the binary tree structure, determined based on the specified iteration type ('RECURSIVE' or
|
|
1336
|
-
* other).
|
|
1337
|
-
*/
|
|
1338
|
-
getRightMost<C extends NodeCallback<OptNodeOrNull<BinaryTreeNode<K, V>>>>(
|
|
1205
|
+
* Finds the rightmost node in a subtree (the node with the largest key in a BST).
|
|
1206
|
+
* @remarks Time O(H), where H is the height of the right spine. O(N) worst-case. Space O(H) for recursive/trampoline stack.
|
|
1207
|
+
*
|
|
1208
|
+
* @template C - The type of the callback function.
|
|
1209
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on the rightmost node.
|
|
1210
|
+
* @param [startNode=this._root] - The subtree root to search from.
|
|
1211
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1212
|
+
* @returns The callback result for the rightmost node.
|
|
1213
|
+
*/
|
|
1214
|
+
getRightMost<C extends NodeCallback<BinaryTreeNode<K, V> | undefined>>(
|
|
1339
1215
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1340
1216
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
1341
1217
|
iterationType: IterationType = this.iterationType
|
|
1342
1218
|
): ReturnType<C> {
|
|
1343
1219
|
if (this.isNIL(startNode)) return callback(undefined);
|
|
1344
1220
|
startNode = this.ensureNode(startNode);
|
|
1345
|
-
if (!startNode) return callback(
|
|
1221
|
+
if (!startNode) return callback(undefined);
|
|
1346
1222
|
|
|
1347
1223
|
if (iterationType === 'RECURSIVE') {
|
|
1348
1224
|
const dfs = (cur: BinaryTreeNode<K, V>): BinaryTreeNode<K, V> => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1225
|
+
const { right } = cur;
|
|
1226
|
+
if (!this.isRealNode(right)) return cur;
|
|
1227
|
+
return dfs(right);
|
|
1351
1228
|
};
|
|
1352
1229
|
|
|
1353
1230
|
return callback(dfs(startNode));
|
|
1354
1231
|
} else {
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
if (!this.isRealNode(
|
|
1358
|
-
return dfs
|
|
1232
|
+
const dfs = makeTrampoline((cur: BinaryTreeNode<K, V>): Trampoline<BinaryTreeNode<K, V>> => {
|
|
1233
|
+
const { right } = cur;
|
|
1234
|
+
if (!this.isRealNode(right)) return cur;
|
|
1235
|
+
return makeTrampolineThunk(() => dfs(right));
|
|
1359
1236
|
});
|
|
1360
1237
|
|
|
1361
1238
|
return callback(dfs(startNode));
|
|
@@ -1363,17 +1240,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1363
1240
|
}
|
|
1364
1241
|
|
|
1365
1242
|
/**
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1243
|
+
* Gets the Morris traversal predecessor (rightmost node in the left subtree, or node itself).
|
|
1244
|
+
* @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).
|
|
1368
1245
|
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
1371
|
-
* @param {BinaryTreeNode<K, V>} node - The `getPredecessor` function you provided seems to be attempting to find the
|
|
1372
|
-
* predecessor of a given node in a binary tree. However, there seems to be a logical issue in the
|
|
1373
|
-
* while loop condition that might cause an infinite loop.
|
|
1374
|
-
* @returns The `getPredecessor` function returns the predecessor node of the input `BinaryTreeNode<K, V>` parameter.
|
|
1375
|
-
* If the left child of the input node exists, it traverses to the rightmost node of the left subtree
|
|
1376
|
-
* to find the predecessor. If the left child does not exist, it returns the input node itself.
|
|
1246
|
+
* @param node - The node to find the predecessor for.
|
|
1247
|
+
* @returns The Morris predecessor.
|
|
1377
1248
|
*/
|
|
1378
1249
|
getPredecessor(node: BinaryTreeNode<K, V>): BinaryTreeNode<K, V> {
|
|
1379
1250
|
if (this.isRealNode(node.left)) {
|
|
@@ -1390,17 +1261,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1390
1261
|
}
|
|
1391
1262
|
|
|
1392
1263
|
/**
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1264
|
+
* Gets the in-order successor of a node in a BST.
|
|
1265
|
+
* @remarks Time O(H), where H is the tree height. O(N) worst-case. Space O(H) (due to `getLeftMost` stack).
|
|
1395
1266
|
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1398
|
-
* @param {K | BinaryTreeNode<K, V> | null} [x] - The `getSuccessor` function takes a parameter `x`, which can be of
|
|
1399
|
-
* type `K`, `BinaryTreeNode<K, V>`, or `null`.
|
|
1400
|
-
* @returns The `getSuccessor` function returns the successor node of the input node `x`. If `x` has
|
|
1401
|
-
* a right child, the function returns the leftmost node in the right subtree of `x`. If `x` does not
|
|
1402
|
-
* have a right child, the function traverses up the parent nodes until it finds a node that is not
|
|
1403
|
-
* the right child of its parent, and returns that node
|
|
1267
|
+
* @param [x] - The node to find the successor of.
|
|
1268
|
+
* @returns The successor node, or null/undefined if none exists.
|
|
1404
1269
|
*/
|
|
1405
1270
|
getSuccessor(x?: K | BinaryTreeNode<K, V> | null): BinaryTreeNode<K, V> | null | undefined {
|
|
1406
1271
|
x = this.ensureNode(x);
|
|
@@ -1436,34 +1301,19 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1436
1301
|
): ReturnType<C>[];
|
|
1437
1302
|
|
|
1438
1303
|
/**
|
|
1439
|
-
*
|
|
1440
|
-
* Space
|
|
1441
|
-
*
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
* @param
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
1447
|
-
* @param
|
|
1448
|
-
*
|
|
1449
|
-
*
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
* or continue searching for all matching nodes. If `onlyOne` is set to `true`, the search will stop
|
|
1453
|
-
* after finding the first matching node
|
|
1454
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
|
|
1455
|
-
* startNode - The `startNode` parameter in the `dfs` function can be one of the following types:
|
|
1456
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `dfs` function
|
|
1457
|
-
* specifies the type of iteration to be performed during the Depth-First Search traversal. It is
|
|
1458
|
-
* used to determine the order in which nodes are visited during the traversal. The possible values
|
|
1459
|
-
* for `iterationType` are typically defined as an enum or a
|
|
1460
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `dfs` function determines whether
|
|
1461
|
-
* null nodes should be included in the depth-first search traversal. If `includeNull` is set to
|
|
1462
|
-
* `true`, null nodes will be included in the traversal process. If it is set to `false`, null nodes
|
|
1463
|
-
* will be skipped
|
|
1464
|
-
* @returns The `dfs` method is returning an array of the return type of the callback function `C`.
|
|
1465
|
-
*/
|
|
1466
|
-
dfs<C extends NodeCallback<OptNodeOrNull<BinaryTreeNode<K, V>>>>(
|
|
1304
|
+
* Performs a Depth-First Search (DFS) traversal.
|
|
1305
|
+
* @remarks Time O(N), visits every node. Space O(H) for the call/explicit stack. O(N) worst-case.
|
|
1306
|
+
*
|
|
1307
|
+
* @template C - The type of the callback function.
|
|
1308
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1309
|
+
* @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
|
|
1310
|
+
* @param [onlyOne=false] - If true, stops after the first callback.
|
|
1311
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1312
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1313
|
+
* @param [includeNull=false] - If true, includes null nodes in the traversal.
|
|
1314
|
+
* @returns An array of callback results.
|
|
1315
|
+
*/
|
|
1316
|
+
dfs<C extends NodeCallback<BinaryTreeNode<K, V> | undefined>>(
|
|
1467
1317
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1468
1318
|
pattern: DFSOrderPattern = 'IN',
|
|
1469
1319
|
onlyOne: boolean = false,
|
|
@@ -1491,27 +1341,15 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1491
1341
|
): ReturnType<C>[];
|
|
1492
1342
|
|
|
1493
1343
|
/**
|
|
1494
|
-
*
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
* @param
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
1502
|
-
* @
|
|
1503
|
-
* function represents the starting point for the breadth-first search traversal in a binary tree. It
|
|
1504
|
-
* can be specified as a key, node, or entry in the binary tree structure. If not provided, the
|
|
1505
|
-
* default value is the root node of the binary
|
|
1506
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `bfs` function
|
|
1507
|
-
* determines the type of iteration to be performed on the binary tree nodes. It can have two
|
|
1508
|
-
* possible values:
|
|
1509
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `bfs` function determines whether
|
|
1510
|
-
* to include `null` values in the breadth-first search traversal of a binary tree. If `includeNull`
|
|
1511
|
-
* is set to `true`, the traversal will include `null` values for nodes that do not have children
|
|
1512
|
-
* (left
|
|
1513
|
-
* @returns The `bfs` function returns an array of values that are the result of applying the
|
|
1514
|
-
* provided callback function to each node in the binary tree in a breadth-first search manner.
|
|
1344
|
+
* Performs a Breadth-First Search (BFS) or Level-Order traversal.
|
|
1345
|
+
* @remarks Time O(N), visits every node. Space O(N) in the worst case for the queue (e.g., a full last level).
|
|
1346
|
+
*
|
|
1347
|
+
* @template C - The type of the callback function.
|
|
1348
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1349
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1350
|
+
* @param [iterationType=this.iterationType] - The traversal method ('RECURSIVE' BFS is less common but supported here).
|
|
1351
|
+
* @param [includeNull=false] - If true, includes null nodes in the traversal.
|
|
1352
|
+
* @returns An array of callback results.
|
|
1515
1353
|
*/
|
|
1516
1354
|
bfs<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
1517
1355
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -1525,6 +1363,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1525
1363
|
const ans: ReturnType<NodeCallback<BinaryTreeNode<K, V> | null>>[] = [];
|
|
1526
1364
|
|
|
1527
1365
|
if (iterationType === 'RECURSIVE') {
|
|
1366
|
+
// This is a "recursive" BFS, which is atypical. It uses a queue but calls itself.
|
|
1528
1367
|
const queue: Queue<OptNodeOrNull<BinaryTreeNode<K, V>>> = new Queue<OptNodeOrNull<BinaryTreeNode<K, V>>>([
|
|
1529
1368
|
startNode
|
|
1530
1369
|
]);
|
|
@@ -1548,10 +1387,10 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1548
1387
|
|
|
1549
1388
|
dfs(0);
|
|
1550
1389
|
} else {
|
|
1390
|
+
// Standard iterative BFS
|
|
1551
1391
|
const queue = new Queue<OptNodeOrNull<BinaryTreeNode<K, V>>>([startNode]);
|
|
1552
1392
|
while (queue.length > 0) {
|
|
1553
|
-
const levelSize = queue.length;
|
|
1554
|
-
|
|
1393
|
+
const levelSize = queue.length; // Not strictly needed here, but good for level-by-level
|
|
1555
1394
|
for (let i = 0; i < levelSize; i++) {
|
|
1556
1395
|
const current = queue.shift()!;
|
|
1557
1396
|
ans.push(callback(current));
|
|
@@ -1570,22 +1409,14 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1570
1409
|
}
|
|
1571
1410
|
|
|
1572
1411
|
/**
|
|
1573
|
-
*
|
|
1574
|
-
* Space
|
|
1412
|
+
* Finds all leaf nodes in the tree.
|
|
1413
|
+
* @remarks Time O(N), visits every node. Space O(H) for recursive stack or O(N) for iterative queue.
|
|
1575
1414
|
*
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1578
|
-
* @param
|
|
1579
|
-
*
|
|
1580
|
-
* @
|
|
1581
|
-
* method is used to specify the starting point for finding and processing the leaves of a binary
|
|
1582
|
-
* tree. It can be provided as either a key, a node, or an entry in the binary tree structure. If not
|
|
1583
|
-
* explicitly provided, the default value
|
|
1584
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `leaves` method
|
|
1585
|
-
* specifies the type of iteration to be performed when collecting the leaves of a binary tree. It
|
|
1586
|
-
* can have two possible values:
|
|
1587
|
-
* @returns The `leaves` method returns an array of values that are the result of applying the
|
|
1588
|
-
* provided callback function to each leaf node in the binary tree.
|
|
1415
|
+
* @template C - The type of the callback function.
|
|
1416
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
|
|
1417
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1418
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1419
|
+
* @returns An array of callback results.
|
|
1589
1420
|
*/
|
|
1590
1421
|
leaves<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
1591
1422
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -1594,9 +1425,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1594
1425
|
): ReturnType<C>[] {
|
|
1595
1426
|
startNode = this.ensureNode(startNode);
|
|
1596
1427
|
const leaves: ReturnType<NodeCallback<BinaryTreeNode<K, V> | null>>[] = [];
|
|
1428
|
+
|
|
1597
1429
|
if (!this.isRealNode(startNode)) return [];
|
|
1598
1430
|
|
|
1599
1431
|
if (iterationType === 'RECURSIVE') {
|
|
1432
|
+
// DFS-based
|
|
1600
1433
|
const dfs = (cur: BinaryTreeNode<K, V>) => {
|
|
1601
1434
|
if (this.isLeaf(cur)) {
|
|
1602
1435
|
leaves.push(callback(cur));
|
|
@@ -1608,7 +1441,9 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1608
1441
|
|
|
1609
1442
|
dfs(startNode);
|
|
1610
1443
|
} else {
|
|
1444
|
+
// BFS-based
|
|
1611
1445
|
const queue = new Queue([startNode]);
|
|
1446
|
+
|
|
1612
1447
|
while (queue.length > 0) {
|
|
1613
1448
|
const cur = queue.shift();
|
|
1614
1449
|
if (this.isRealNode(cur)) {
|
|
@@ -1639,28 +1474,15 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1639
1474
|
): ReturnType<C>[][];
|
|
1640
1475
|
|
|
1641
1476
|
/**
|
|
1642
|
-
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
* @param
|
|
1648
|
-
*
|
|
1649
|
-
*
|
|
1650
|
-
* @
|
|
1651
|
-
* `listLevels` function represents the starting point for traversing the binary tree. It can be
|
|
1652
|
-
* either a key, a node, or an entry in the binary tree. If not provided, the default value is the
|
|
1653
|
-
* root of the binary tree.
|
|
1654
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `listLevels` function
|
|
1655
|
-
* determines the type of iteration to be performed on the binary tree nodes. It can have two
|
|
1656
|
-
* possible values:
|
|
1657
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `listLevels` method determines
|
|
1658
|
-
* whether or not to include null nodes in the traversal of the binary tree. If `includeNull` is set
|
|
1659
|
-
* to `true`, the traversal will include null nodes in the levels of the tree. If set to `false`,
|
|
1660
|
-
* null
|
|
1661
|
-
* @returns The `listLevels` method returns an array of arrays, where each inner array represents a
|
|
1662
|
-
* level in a binary tree. Each inner array contains the return value of the provided callback
|
|
1663
|
-
* function applied to the nodes at that level.
|
|
1477
|
+
* Returns a 2D array of nodes, grouped by level.
|
|
1478
|
+
* @remarks Time O(N), visits every node. Space O(N) for the result array and the queue/stack.
|
|
1479
|
+
*
|
|
1480
|
+
* @template C - The type of the callback function.
|
|
1481
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1482
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1483
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1484
|
+
* @param [includeNull=false] - If true, includes null nodes.
|
|
1485
|
+
* @returns A 2D array of callback results.
|
|
1664
1486
|
*/
|
|
1665
1487
|
listLevels<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
1666
1488
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -1670,9 +1492,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1670
1492
|
): ReturnType<C>[][] {
|
|
1671
1493
|
startNode = this.ensureNode(startNode);
|
|
1672
1494
|
const levelsNodes: ReturnType<C>[][] = [];
|
|
1495
|
+
|
|
1673
1496
|
if (!startNode) return levelsNodes;
|
|
1674
1497
|
|
|
1675
1498
|
if (iterationType === 'RECURSIVE') {
|
|
1499
|
+
// Pre-order DFS based level listing
|
|
1676
1500
|
const _recursive = (node: BinaryTreeNode<K, V> | null, level: number) => {
|
|
1677
1501
|
if (!levelsNodes[level]) levelsNodes[level] = [];
|
|
1678
1502
|
levelsNodes[level].push(callback(node));
|
|
@@ -1687,6 +1511,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1687
1511
|
|
|
1688
1512
|
_recursive(startNode, 0);
|
|
1689
1513
|
} else {
|
|
1514
|
+
// Iterative DFS based level listing
|
|
1690
1515
|
const stack: [BinaryTreeNode<K, V> | null, number][] = [[startNode, 0]];
|
|
1691
1516
|
|
|
1692
1517
|
while (stack.length > 0) {
|
|
@@ -1716,24 +1541,14 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1716
1541
|
): ReturnType<C>[];
|
|
1717
1542
|
|
|
1718
1543
|
/**
|
|
1719
|
-
*
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
* @param
|
|
1725
|
-
*
|
|
1726
|
-
*
|
|
1727
|
-
* @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `morris` function specifies
|
|
1728
|
-
* the type of Depth-First Search (DFS) order pattern to traverse the binary tree. The possible
|
|
1729
|
-
* values for the `pattern` parameter are:
|
|
1730
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `morris`
|
|
1731
|
-
* function is the starting point for the Morris traversal algorithm. It represents the root node of
|
|
1732
|
-
* the binary tree or the node from which the traversal should begin. It can be provided as either a
|
|
1733
|
-
* key, a node, an entry, or a reference
|
|
1734
|
-
* @returns The `morris` function is returning an array of values that are the result of applying the
|
|
1735
|
-
* provided callback function to each node in the binary tree in the specified order pattern (IN,
|
|
1736
|
-
* PRE, or POST).
|
|
1544
|
+
* Performs a Morris (threaded) traversal.
|
|
1545
|
+
* @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).
|
|
1546
|
+
*
|
|
1547
|
+
* @template C - The type of the callback function.
|
|
1548
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
1549
|
+
* @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
|
|
1550
|
+
* @param [startNode=this._root] - The node to start from.
|
|
1551
|
+
* @returns An array of callback results.
|
|
1737
1552
|
*/
|
|
1738
1553
|
morris<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
1739
1554
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -1741,10 +1556,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1741
1556
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root
|
|
1742
1557
|
): ReturnType<C>[] {
|
|
1743
1558
|
startNode = this.ensureNode(startNode);
|
|
1559
|
+
|
|
1744
1560
|
if (!startNode) return [];
|
|
1745
1561
|
const ans: ReturnType<NodeCallback<BinaryTreeNode<K, V> | null>>[] = [];
|
|
1746
1562
|
|
|
1747
1563
|
let cur: BinaryTreeNode<K, V> | null | undefined = startNode;
|
|
1564
|
+
|
|
1565
|
+
// Helper to reverse a linked list (formed by right pointers)
|
|
1748
1566
|
const _reverseEdge = (node: BinaryTreeNode<K, V> | null | undefined) => {
|
|
1749
1567
|
let pre: BinaryTreeNode<K, V> | null | undefined = null;
|
|
1750
1568
|
let next: BinaryTreeNode<K, V> | null | undefined = null;
|
|
@@ -1756,25 +1574,32 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1756
1574
|
}
|
|
1757
1575
|
return pre;
|
|
1758
1576
|
};
|
|
1577
|
+
|
|
1578
|
+
// Helper to print the reversed edge (for post-order)
|
|
1759
1579
|
const _printEdge = (node: BinaryTreeNode<K, V> | null | undefined) => {
|
|
1760
1580
|
const tail: BinaryTreeNode<K, V> | null | undefined = _reverseEdge(node);
|
|
1761
1581
|
let cur: BinaryTreeNode<K, V> | null | undefined = tail;
|
|
1582
|
+
|
|
1762
1583
|
while (cur) {
|
|
1763
1584
|
ans.push(callback(cur));
|
|
1764
1585
|
cur = cur.right;
|
|
1765
1586
|
}
|
|
1766
|
-
|
|
1587
|
+
|
|
1588
|
+
_reverseEdge(tail); // Restore the edge
|
|
1767
1589
|
};
|
|
1590
|
+
|
|
1768
1591
|
switch (pattern) {
|
|
1769
1592
|
case 'IN':
|
|
1770
1593
|
while (cur) {
|
|
1771
1594
|
if (cur.left) {
|
|
1772
1595
|
const predecessor = this.getPredecessor(cur);
|
|
1773
1596
|
if (!predecessor.right) {
|
|
1597
|
+
// Create thread
|
|
1774
1598
|
predecessor.right = cur;
|
|
1775
1599
|
cur = cur.left;
|
|
1776
1600
|
continue;
|
|
1777
1601
|
} else {
|
|
1602
|
+
// Remove thread
|
|
1778
1603
|
predecessor.right = null;
|
|
1779
1604
|
}
|
|
1780
1605
|
}
|
|
@@ -1787,11 +1612,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1787
1612
|
if (cur.left) {
|
|
1788
1613
|
const predecessor = this.getPredecessor(cur);
|
|
1789
1614
|
if (!predecessor.right) {
|
|
1615
|
+
// Create thread and visit
|
|
1790
1616
|
predecessor.right = cur;
|
|
1791
1617
|
ans.push(callback(cur));
|
|
1792
1618
|
cur = cur.left;
|
|
1793
1619
|
continue;
|
|
1794
1620
|
} else {
|
|
1621
|
+
// Remove thread
|
|
1795
1622
|
predecessor.right = null;
|
|
1796
1623
|
}
|
|
1797
1624
|
} else {
|
|
@@ -1805,115 +1632,81 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1805
1632
|
if (cur.left) {
|
|
1806
1633
|
const predecessor = this.getPredecessor(cur);
|
|
1807
1634
|
if (predecessor.right === null) {
|
|
1635
|
+
// Create thread
|
|
1808
1636
|
predecessor.right = cur;
|
|
1809
1637
|
cur = cur.left;
|
|
1810
1638
|
continue;
|
|
1811
1639
|
} else {
|
|
1640
|
+
// Remove thread and print right spine of left child
|
|
1812
1641
|
predecessor.right = null;
|
|
1813
1642
|
_printEdge(cur.left);
|
|
1814
1643
|
}
|
|
1815
1644
|
}
|
|
1816
1645
|
cur = cur.right;
|
|
1817
1646
|
}
|
|
1818
|
-
_printEdge(startNode);
|
|
1647
|
+
_printEdge(startNode); // Print the right spine of the root
|
|
1819
1648
|
break;
|
|
1820
1649
|
}
|
|
1821
1650
|
return ans;
|
|
1822
1651
|
}
|
|
1823
1652
|
|
|
1824
1653
|
/**
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1654
|
+
* Clones the tree.
|
|
1655
|
+
* @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.
|
|
1827
1656
|
*
|
|
1828
|
-
*
|
|
1829
|
-
* search.
|
|
1830
|
-
* @returns The `clone()` method is returning a cloned copy of the tree with the same structure and
|
|
1831
|
-
* values as the original tree. The method creates a new tree, iterates over the nodes of the
|
|
1832
|
-
* original tree using breadth-first search (bfs), and adds the nodes to the new tree. If a node in
|
|
1833
|
-
* the original tree is null, a null node is added to the cloned tree. If a node
|
|
1657
|
+
* @returns A new, cloned instance of the tree.
|
|
1834
1658
|
*/
|
|
1835
|
-
clone() {
|
|
1836
|
-
const
|
|
1837
|
-
this._clone(
|
|
1838
|
-
return
|
|
1659
|
+
clone(): this {
|
|
1660
|
+
const out = this._createInstance<K, V, R>();
|
|
1661
|
+
this._clone(out);
|
|
1662
|
+
return out;
|
|
1839
1663
|
}
|
|
1840
1664
|
|
|
1841
1665
|
/**
|
|
1842
|
-
*
|
|
1843
|
-
*
|
|
1666
|
+
* Creates a new tree containing only the entries that satisfy the predicate.
|
|
1667
|
+
* @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.
|
|
1844
1668
|
*
|
|
1845
|
-
*
|
|
1846
|
-
*
|
|
1847
|
-
* @
|
|
1848
|
-
* called with four arguments: the `value` of the current entry, the `key` of the current entry, the
|
|
1849
|
-
* `index` of the current entry in the iteration, and the reference to the tree itself (`
|
|
1850
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `filter` method allows you to specify the
|
|
1851
|
-
* value of `this` that should be used when executing the `predicate` function. This is useful when
|
|
1852
|
-
* the `predicate` function relies on the context of a specific object or value. By providing a
|
|
1853
|
-
* `thisArg
|
|
1854
|
-
* @returns The `filter` method is returning a new tree that contains entries that pass the provided
|
|
1855
|
-
* predicate function.
|
|
1669
|
+
* @param predicate - A function to test each [key, value] pair.
|
|
1670
|
+
* @param [thisArg] - `this` context for the predicate.
|
|
1671
|
+
* @returns A new, filtered tree.
|
|
1856
1672
|
*/
|
|
1857
|
-
filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?:
|
|
1858
|
-
const
|
|
1859
|
-
let
|
|
1860
|
-
for (const [
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
* @
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
* comparators, initial
|
|
1881
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `map` method is used to specify the value
|
|
1882
|
-
* of `this` when executing the `callback` function. It allows you to set the context (value of
|
|
1883
|
-
* `this`) within the callback function. If `thisArg` is provided, it will be passed
|
|
1884
|
-
* @returns The `map` function is returning a new `BinaryTree` instance filled with entries that are
|
|
1885
|
-
* the result of applying the provided `callback` function to each entry in the original tree.
|
|
1886
|
-
*/
|
|
1887
|
-
map(
|
|
1888
|
-
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
1889
|
-
options?: BinaryTreeOptions<MK, MV, MR>,
|
|
1890
|
-
thisArg?: any
|
|
1673
|
+
filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
|
|
1674
|
+
const out = this._createInstance<K, V, R>();
|
|
1675
|
+
let i = 0;
|
|
1676
|
+
for (const [k, v] of this) if (predicate.call(thisArg, k, v, i++, this)) out.add([k, v]);
|
|
1677
|
+
return out;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/**
|
|
1681
|
+
* Creates a new tree by mapping each [key, value] pair to a new entry.
|
|
1682
|
+
* @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.
|
|
1683
|
+
*
|
|
1684
|
+
* @template MK - New key type.
|
|
1685
|
+
* @template MV - New value type.
|
|
1686
|
+
* @template MR - New raw type.
|
|
1687
|
+
* @param cb - A function to map each [key, value] pair.
|
|
1688
|
+
* @param [options] - Options for the new tree.
|
|
1689
|
+
* @param [thisArg] - `this` context for the callback.
|
|
1690
|
+
* @returns A new, mapped tree.
|
|
1691
|
+
*/
|
|
1692
|
+
map<MK = K, MV = V, MR extends object = object>(
|
|
1693
|
+
cb: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
1694
|
+
options?: Partial<BinaryTreeOptions<MK, MV, MR>>,
|
|
1695
|
+
thisArg?: unknown
|
|
1891
1696
|
): BinaryTree<MK, MV, MR> {
|
|
1892
|
-
const
|
|
1893
|
-
let
|
|
1894
|
-
for (const [
|
|
1895
|
-
|
|
1896
|
-
}
|
|
1897
|
-
return newTree;
|
|
1697
|
+
const out = this._createLike<MK, MV, MR>([], options);
|
|
1698
|
+
let i = 0;
|
|
1699
|
+
for (const [k, v] of this) out.add(cb.call(thisArg, k, v, i++, this));
|
|
1700
|
+
return out;
|
|
1898
1701
|
}
|
|
1899
1702
|
|
|
1900
1703
|
/**
|
|
1901
|
-
*
|
|
1902
|
-
* Space
|
|
1704
|
+
* Generates a string representation of the tree for visualization.
|
|
1705
|
+
* @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.
|
|
1903
1706
|
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
* @
|
|
1907
|
-
* `toVisual` method is used to specify the starting point for visualizing the binary tree structure.
|
|
1908
|
-
* It can be a node, key, entry, or the root of the tree. If no specific starting point is provided,
|
|
1909
|
-
* the default is set to the root
|
|
1910
|
-
* @param {BinaryTreePrintOptions} [options] - The `options` parameter in the `toVisual` method is an
|
|
1911
|
-
* object that contains the following properties:
|
|
1912
|
-
* @returns The `override toVisual` method returns a string that represents the visual display of the
|
|
1913
|
-
* binary tree based on the provided options for showing undefined, null, and Red-Black NIL nodes.
|
|
1914
|
-
* The method constructs the visual representation by calling the `_displayAux` method and appending
|
|
1915
|
-
* the lines to the output string. The final output string contains the visual representation of the
|
|
1916
|
-
* binary tree with the specified options.
|
|
1707
|
+
* @param [startNode=this._root] - The node to start printing from.
|
|
1708
|
+
* @param [options] - Options to control the output (e.g., show nulls).
|
|
1709
|
+
* @returns The string representation of the tree.
|
|
1917
1710
|
*/
|
|
1918
1711
|
override toVisual(
|
|
1919
1712
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1942,19 +1735,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1942
1735
|
}
|
|
1943
1736
|
|
|
1944
1737
|
/**
|
|
1945
|
-
*
|
|
1946
|
-
* Space
|
|
1738
|
+
* Prints a visual representation of the tree to the console.
|
|
1739
|
+
* @remarks Time O(N) (via `toVisual`). Space O(N*H) or O(N^2) (via `toVisual`).
|
|
1947
1740
|
*
|
|
1948
|
-
*
|
|
1949
|
-
*
|
|
1950
|
-
* @param {BinaryTreePrintOptions} [options] - The `options` parameter is used to specify the
|
|
1951
|
-
* printing options for the binary tree. It is an optional parameter that allows you to customize how
|
|
1952
|
-
* the binary tree is printed, such as choosing between different traversal orders or formatting
|
|
1953
|
-
* options.
|
|
1954
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
|
|
1955
|
-
* `override print` method is used to specify the starting point for printing the binary tree. It can
|
|
1956
|
-
* be either a key, a node, an entry, or the root of the tree. If no specific starting point is
|
|
1957
|
-
* provided, the default value is set to
|
|
1741
|
+
* @param [options] - Options to control the output.
|
|
1742
|
+
* @param [startNode=this._root] - The node to start printing from.
|
|
1958
1743
|
*/
|
|
1959
1744
|
override print(
|
|
1960
1745
|
options?: BinaryTreePrintOptions,
|
|
@@ -1963,60 +1748,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1963
1748
|
console.log(this.toVisual(startNode, options));
|
|
1964
1749
|
}
|
|
1965
1750
|
|
|
1966
|
-
protected _clone(cloned: BinaryTree<K, V, R, MK, MV, MR>) {
|
|
1967
|
-
this.bfs(
|
|
1968
|
-
node => {
|
|
1969
|
-
if (node === null) cloned.add(null);
|
|
1970
|
-
else {
|
|
1971
|
-
if (this._isMapMode) cloned.add([node.key, this._store.get(node.key)]);
|
|
1972
|
-
else cloned.add([node.key, node.value]);
|
|
1973
|
-
}
|
|
1974
|
-
},
|
|
1975
|
-
this._root,
|
|
1976
|
-
this.iterationType,
|
|
1977
|
-
true
|
|
1978
|
-
);
|
|
1979
|
-
if (this._isMapMode) cloned._store = this._store;
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
/**
|
|
1983
|
-
* Time Complexity: O(1)
|
|
1984
|
-
* Space Complexity: O(1)
|
|
1985
|
-
*
|
|
1986
|
-
* The function `keyValueNodeEntryRawToNodeAndValue` converts various input types into a node object
|
|
1987
|
-
* or returns null.
|
|
1988
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The
|
|
1989
|
-
* `keyValueNodeEntryRawToNodeAndValue` function takes in a parameter `keyNodeOrEntry`, which
|
|
1990
|
-
* can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. This parameter represents either a key, a
|
|
1991
|
-
* node, an entry
|
|
1992
|
-
* @param {V} [value] - The `value` parameter in the `keyValueNodeEntryRawToNodeAndValue` function is
|
|
1993
|
-
* an optional parameter of type `V`. It represents the value associated with the key in the node
|
|
1994
|
-
* being created. If a `value` is provided, it will be used when creating the node. If
|
|
1995
|
-
* @returns The `keyValueNodeEntryRawToNodeAndValue` function returns an optional node
|
|
1996
|
-
* (`BinaryTreeNode<K, V> | null | undefined`) based on the input parameters provided. The function checks the type of the
|
|
1997
|
-
* input parameter (`keyNodeOrEntry`) and processes it accordingly to return a node or null
|
|
1998
|
-
* value.
|
|
1999
|
-
*/
|
|
2000
|
-
protected _keyValueNodeOrEntryToNodeAndValue(
|
|
2001
|
-
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
2002
|
-
value?: V
|
|
2003
|
-
): [BinaryTreeNode<K, V> | null | undefined, V | undefined] {
|
|
2004
|
-
if (keyNodeOrEntry === undefined) return [undefined, undefined];
|
|
2005
|
-
if (keyNodeOrEntry === null) return [null, undefined];
|
|
2006
|
-
|
|
2007
|
-
if (this.isNode(keyNodeOrEntry)) return [keyNodeOrEntry, value];
|
|
2008
|
-
|
|
2009
|
-
if (this.isEntry(keyNodeOrEntry)) {
|
|
2010
|
-
const [key, entryValue] = keyNodeOrEntry;
|
|
2011
|
-
if (key === undefined) return [undefined, undefined];
|
|
2012
|
-
else if (key === null) return [null, undefined];
|
|
2013
|
-
const finalValue = value ?? entryValue;
|
|
2014
|
-
return [this.createNode(key, finalValue), finalValue];
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
return [this.createNode(keyNodeOrEntry, value), value];
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
1751
|
protected _dfs<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
2021
1752
|
callback: C,
|
|
2022
1753
|
pattern?: DFSOrderPattern,
|
|
@@ -2031,49 +1762,21 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2031
1762
|
): ReturnType<C>[];
|
|
2032
1763
|
|
|
2033
1764
|
/**
|
|
2034
|
-
*
|
|
2035
|
-
* Space
|
|
2036
|
-
*
|
|
2037
|
-
*
|
|
2038
|
-
*
|
|
2039
|
-
* @param
|
|
2040
|
-
*
|
|
2041
|
-
*
|
|
2042
|
-
* @param
|
|
2043
|
-
*
|
|
2044
|
-
*
|
|
2045
|
-
* @param
|
|
2046
|
-
*
|
|
2047
|
-
*
|
|
2048
|
-
*
|
|
2049
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
|
|
2050
|
-
* startNode - The `startNode` parameter in the `_dfs` method is used to specify the starting node
|
|
2051
|
-
* for the depth-first search traversal. It can be provided in different forms:
|
|
2052
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `_dfs` method
|
|
2053
|
-
* specifies whether the traversal should be done recursively or iteratively. It can have two
|
|
2054
|
-
* possible values:
|
|
2055
|
-
* @param [includeNull=false] - The `includeNull` parameter in the `_dfs` method determines whether
|
|
2056
|
-
* null nodes should be included in the traversal process. If `includeNull` is set to `true`, the
|
|
2057
|
-
* method will consider null nodes as valid nodes to visit or process. If `includeNull` is set to
|
|
2058
|
-
* `false`,
|
|
2059
|
-
* @param shouldVisitLeft - The `shouldVisitLeft` parameter in the `_dfs` method is a function that
|
|
2060
|
-
* determines whether the left child of a node should be visited during the Depth-First Search
|
|
2061
|
-
* traversal. By default, it checks if the node is not null or undefined before visiting the left
|
|
2062
|
-
* child. You can customize this behavior
|
|
2063
|
-
* @param shouldVisitRight - The `shouldVisitRight` parameter in the `_dfs` method is a function that
|
|
2064
|
-
* determines whether to visit the right child node of the current node during a depth-first search
|
|
2065
|
-
* traversal. The default implementation of this function checks if the node is not null or undefined
|
|
2066
|
-
* before deciding to visit it.
|
|
2067
|
-
* @param shouldVisitRoot - The `shouldVisitRoot` parameter in the `_dfs` method is a function that
|
|
2068
|
-
* determines whether a given node should be visited during the depth-first search traversal. The
|
|
2069
|
-
* function takes a node as an argument and returns a boolean value indicating whether the node
|
|
2070
|
-
* should be visited.
|
|
2071
|
-
* @param shouldProcessRoot - The `shouldProcessRoot` parameter in the `_dfs` method is a function
|
|
2072
|
-
* that determines whether the root node should be processed during the Depth-First Search traversal.
|
|
2073
|
-
* It takes a node (BinaryTreeNode<K, V> | null | undefined) as input and returns a boolean value. If
|
|
2074
|
-
* the function
|
|
2075
|
-
* @returns The `_dfs` method returns an array of the return type of the provided callback function
|
|
2076
|
-
* `C`.
|
|
1765
|
+
* (Protected) Core DFS implementation.
|
|
1766
|
+
* @remarks Time O(N), visits every node satisfying predicates. Space O(H) for call/explicit stack. O(N) worst-case.
|
|
1767
|
+
*
|
|
1768
|
+
* @template C - Callback type.
|
|
1769
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on nodes.
|
|
1770
|
+
* @param [pattern='IN'] - Traversal order.
|
|
1771
|
+
* @param [onlyOne=false] - Stop after first match.
|
|
1772
|
+
* @param [startNode=this._root] - Starting node.
|
|
1773
|
+
* @param [iterationType=this.iterationType] - Traversal method.
|
|
1774
|
+
* @param [includeNull=false] - Include nulls.
|
|
1775
|
+
* @param [shouldVisitLeft] - Predicate to traverse left.
|
|
1776
|
+
* @param [shouldVisitRight] - Predicate to traverse right.
|
|
1777
|
+
* @param [shouldVisitRoot] - Predicate to visit root.
|
|
1778
|
+
* @param [shouldProcessRoot] - Predicate to process root.
|
|
1779
|
+
* @returns Array of callback results.
|
|
2077
1780
|
*/
|
|
2078
1781
|
protected _dfs<C extends NodeCallback<BinaryTreeNode<K, V> | null>>(
|
|
2079
1782
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -2135,6 +1838,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2135
1838
|
|
|
2136
1839
|
dfs(startNode);
|
|
2137
1840
|
} else {
|
|
1841
|
+
// Iterative
|
|
2138
1842
|
const stack: DFSStackItem<BinaryTreeNode<K, V>>[] = [{ opt: DFSOperation.VISIT, node: startNode }];
|
|
2139
1843
|
|
|
2140
1844
|
const pushLeft = (cur: DFSStackItem<BinaryTreeNode<K, V>>) => {
|
|
@@ -2157,6 +1861,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2157
1861
|
if (onlyOne) return ans;
|
|
2158
1862
|
}
|
|
2159
1863
|
} else {
|
|
1864
|
+
// VISIT
|
|
2160
1865
|
switch (pattern) {
|
|
2161
1866
|
case 'IN':
|
|
2162
1867
|
pushRight(cur);
|
|
@@ -2182,19 +1887,11 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2182
1887
|
}
|
|
2183
1888
|
|
|
2184
1889
|
/**
|
|
2185
|
-
*
|
|
2186
|
-
* Space
|
|
1890
|
+
* (Protected) Gets the iterator for the tree (default in-order).
|
|
1891
|
+
* @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.
|
|
2187
1892
|
*
|
|
2188
|
-
*
|
|
2189
|
-
*
|
|
2190
|
-
* @param node - The `node` parameter in the `_getIterator` method represents the current node being
|
|
2191
|
-
* processed during iteration. It is initially set to the root node of the data structure (or the
|
|
2192
|
-
* node passed as an argument), and then it is traversed through the data structure based on the
|
|
2193
|
-
* iteration type specified (`ITER
|
|
2194
|
-
* @returns The `_getIterator` method returns an IterableIterator containing key-value pairs of nodes
|
|
2195
|
-
* in a binary tree structure. The method uses an iterative approach to traverse the tree based on
|
|
2196
|
-
* the `iterationType` property. If the `iterationType` is set to 'ITERATIVE', the method uses a
|
|
2197
|
-
* stack to perform an in-order traversal of the tree. If the `iterationType` is not 'ITERATIVE
|
|
1893
|
+
* @param [node=this._root] - The node to start iteration from.
|
|
1894
|
+
* @returns An iterator for [key, value] pairs.
|
|
2198
1895
|
*/
|
|
2199
1896
|
protected *_getIterator(node = this._root): IterableIterator<[K, V | undefined]> {
|
|
2200
1897
|
if (!node) return;
|
|
@@ -2204,25 +1901,31 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2204
1901
|
let current: BinaryTreeNode<K, V> | null | undefined = node;
|
|
2205
1902
|
|
|
2206
1903
|
while (current || stack.length > 0) {
|
|
1904
|
+
// Go to the leftmost node
|
|
2207
1905
|
while (this.isRealNode(current)) {
|
|
2208
1906
|
stack.push(current);
|
|
2209
1907
|
current = current.left;
|
|
2210
1908
|
}
|
|
2211
1909
|
|
|
1910
|
+
// Visit the node
|
|
2212
1911
|
current = stack.pop();
|
|
2213
1912
|
|
|
2214
1913
|
if (this.isRealNode(current)) {
|
|
2215
1914
|
if (this._isMapMode) yield [current.key, this._store.get(current.key)];
|
|
2216
1915
|
else yield [current.key, current.value];
|
|
1916
|
+
// Move to the right subtree
|
|
2217
1917
|
current = current.right;
|
|
2218
1918
|
}
|
|
2219
1919
|
}
|
|
2220
1920
|
} else {
|
|
1921
|
+
// Recursive in-order traversal
|
|
2221
1922
|
if (node.left && this.isRealNode(node)) {
|
|
2222
1923
|
yield* this[Symbol.iterator](node.left);
|
|
2223
1924
|
}
|
|
1925
|
+
|
|
2224
1926
|
if (this._isMapMode) yield [node.key, this._store.get(node.key)];
|
|
2225
1927
|
else yield [node.key, node.value];
|
|
1928
|
+
|
|
2226
1929
|
if (node.right && this.isRealNode(node)) {
|
|
2227
1930
|
yield* this[Symbol.iterator](node.right);
|
|
2228
1931
|
}
|
|
@@ -2230,28 +1933,138 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2230
1933
|
}
|
|
2231
1934
|
|
|
2232
1935
|
/**
|
|
2233
|
-
*
|
|
2234
|
-
*
|
|
1936
|
+
* (Protected) Default callback function, returns the node's key.
|
|
1937
|
+
* @remarks Time O(1)
|
|
1938
|
+
*
|
|
1939
|
+
* @param node - The node.
|
|
1940
|
+
* @returns The node's key or undefined.
|
|
1941
|
+
*/
|
|
1942
|
+
protected _DEFAULT_NODE_CALLBACK = (node: BinaryTreeNode<K, V> | null | undefined) => (node ? node.key : undefined);
|
|
1943
|
+
|
|
1944
|
+
/**
|
|
1945
|
+
* (Protected) Snapshots the current tree's configuration options.
|
|
1946
|
+
* @remarks Time O(1)
|
|
1947
|
+
*
|
|
1948
|
+
* @template TK, TV, TR - Generic types for the options.
|
|
1949
|
+
* @returns The options object.
|
|
1950
|
+
*/
|
|
1951
|
+
protected _snapshotOptions<TK = K, TV = V, TR extends object = R>(): BinaryTreeOptions<TK, TV, TR> {
|
|
1952
|
+
return {
|
|
1953
|
+
iterationType: this.iterationType,
|
|
1954
|
+
toEntryFn: this.toEntryFn as unknown as BinaryTreeOptions<TK, TV, TR>['toEntryFn'],
|
|
1955
|
+
isMapMode: this.isMapMode,
|
|
1956
|
+
isDuplicate: this.isDuplicate
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
/**
|
|
1961
|
+
* (Protected) Creates a new, empty instance of the same tree constructor.
|
|
1962
|
+
* @remarks Time O(1)
|
|
1963
|
+
*
|
|
1964
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
1965
|
+
* @param [options] - Options for the new tree.
|
|
1966
|
+
* @returns A new, empty tree.
|
|
1967
|
+
*/
|
|
1968
|
+
protected _createInstance<TK = K, TV = V, TR extends object = R>(
|
|
1969
|
+
options?: Partial<BinaryTreeOptions<TK, TV, TR>>
|
|
1970
|
+
): this {
|
|
1971
|
+
const Ctor = this.constructor as unknown as new (
|
|
1972
|
+
iter?: Iterable<TK | BinaryTreeNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
1973
|
+
opts?: BinaryTreeOptions<TK, TV, TR>
|
|
1974
|
+
) => BinaryTree<TK, TV, TR>;
|
|
1975
|
+
return new Ctor([], { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as this;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
/**
|
|
1979
|
+
* (Protected) Creates a new instance of the same tree constructor, potentially with different generic types.
|
|
1980
|
+
* @remarks Time O(N) (or as per constructor) due to processing the iterable.
|
|
1981
|
+
*
|
|
1982
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
1983
|
+
* @param [iter=[]] - An iterable to populate the new tree.
|
|
1984
|
+
* @param [options] - Options for the new tree.
|
|
1985
|
+
* @returns A new tree.
|
|
1986
|
+
*/
|
|
1987
|
+
protected _createLike<TK = K, TV = V, TR extends object = R>(
|
|
1988
|
+
iter: Iterable<TK | BinaryTreeNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR> = [],
|
|
1989
|
+
options?: Partial<BinaryTreeOptions<TK, TV, TR>>
|
|
1990
|
+
): BinaryTree<TK, TV, TR> {
|
|
1991
|
+
const Ctor = this.constructor as unknown as new (
|
|
1992
|
+
iter?: Iterable<TK | BinaryTreeNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
1993
|
+
opts?: BinaryTreeOptions<TK, TV, TR>
|
|
1994
|
+
) => BinaryTree<TK, TV, TR>;
|
|
1995
|
+
return new Ctor(iter, { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as BinaryTree<
|
|
1996
|
+
TK,
|
|
1997
|
+
TV,
|
|
1998
|
+
TR
|
|
1999
|
+
>;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
/**
|
|
2003
|
+
* (Protected) Converts a key, node, or entry into a standardized [node, value] tuple.
|
|
2004
|
+
* @remarks Time O(1)
|
|
2005
|
+
*
|
|
2006
|
+
* @param keyNodeOrEntry - The input item.
|
|
2007
|
+
* @param [value] - An optional value (used if input is just a key).
|
|
2008
|
+
* @returns A tuple of [node, value].
|
|
2009
|
+
*/
|
|
2010
|
+
protected _keyValueNodeOrEntryToNodeAndValue(
|
|
2011
|
+
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
2012
|
+
value?: V
|
|
2013
|
+
): [BinaryTreeNode<K, V> | null | undefined, V | undefined] {
|
|
2014
|
+
if (keyNodeOrEntry === undefined) return [undefined, undefined];
|
|
2015
|
+
if (keyNodeOrEntry === null) return [null, undefined];
|
|
2016
|
+
|
|
2017
|
+
if (this.isNode(keyNodeOrEntry)) return [keyNodeOrEntry, value];
|
|
2018
|
+
|
|
2019
|
+
if (this.isEntry(keyNodeOrEntry)) {
|
|
2020
|
+
const [key, entryValue] = keyNodeOrEntry;
|
|
2021
|
+
if (key === undefined) return [undefined, undefined];
|
|
2022
|
+
else if (key === null) return [null, undefined];
|
|
2023
|
+
const finalValue = value ?? entryValue;
|
|
2024
|
+
return [this._createNode(key, finalValue), finalValue];
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
return [this._createNode(keyNodeOrEntry, value), value];
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
/**
|
|
2031
|
+
* (Protected) Helper for cloning. Performs a BFS and adds all nodes to the new tree.
|
|
2032
|
+
* @remarks Time O(N * M) (O(N) BFS + O(M) `add` for each node).
|
|
2235
2033
|
*
|
|
2236
|
-
*
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2034
|
+
* @param cloned - The new, empty tree instance to populate.
|
|
2035
|
+
*/
|
|
2036
|
+
protected _clone(cloned: BinaryTree<K, V, R>) {
|
|
2037
|
+
// Use BFS with nulls to preserve the tree structure
|
|
2038
|
+
this.bfs(
|
|
2039
|
+
node => {
|
|
2040
|
+
if (node === null) cloned.add(null);
|
|
2041
|
+
else {
|
|
2042
|
+
if (this._isMapMode) cloned.add([node.key, this._store.get(node.key)]);
|
|
2043
|
+
else cloned.add([node.key, node.value]);
|
|
2044
|
+
}
|
|
2045
|
+
},
|
|
2046
|
+
this._root,
|
|
2047
|
+
this.iterationType,
|
|
2048
|
+
true // Include nulls
|
|
2049
|
+
);
|
|
2050
|
+
if (this._isMapMode) cloned._store = this._store;
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
/**
|
|
2054
|
+
* (Protected) Recursive helper for `toVisual`.
|
|
2055
|
+
* @remarks Time O(N), Space O(N*H) or O(N^2)
|
|
2056
|
+
*
|
|
2057
|
+
* @param node - The current node.
|
|
2058
|
+
* @param options - Print options.
|
|
2059
|
+
* @returns Layout information for this subtree.
|
|
2246
2060
|
*/
|
|
2247
2061
|
protected _displayAux(
|
|
2248
2062
|
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2249
2063
|
options: BinaryTreePrintOptions
|
|
2250
2064
|
): NodeDisplayLayout {
|
|
2251
2065
|
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
2252
|
-
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
|
|
2066
|
+
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0]; // Represents an empty spot
|
|
2253
2067
|
|
|
2254
|
-
// Check if node is null or undefined or key is NaN
|
|
2255
2068
|
if (node === null && !isShowNull) {
|
|
2256
2069
|
return emptyDisplayLayout;
|
|
2257
2070
|
} else if (node === undefined && !isShowUndefined) {
|
|
@@ -2259,8 +2072,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2259
2072
|
} else if (this.isNIL(node) && !isShowRedBlackNIL) {
|
|
2260
2073
|
return emptyDisplayLayout;
|
|
2261
2074
|
} else if (node !== null && node !== undefined) {
|
|
2262
|
-
//
|
|
2263
|
-
|
|
2075
|
+
// Real node
|
|
2264
2076
|
const key = node.key,
|
|
2265
2077
|
line = this.isNIL(node) ? 'S' : String(key),
|
|
2266
2078
|
width = line.length;
|
|
@@ -2272,13 +2084,18 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2272
2084
|
this._displayAux(node.right, options)
|
|
2273
2085
|
);
|
|
2274
2086
|
} else {
|
|
2275
|
-
//
|
|
2087
|
+
// Null or Undefined
|
|
2276
2088
|
const line = node === undefined ? 'U' : 'N',
|
|
2277
2089
|
width = line.length;
|
|
2278
2090
|
|
|
2091
|
+
// Treat as a leaf
|
|
2279
2092
|
return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0]);
|
|
2280
2093
|
}
|
|
2281
2094
|
|
|
2095
|
+
/**
|
|
2096
|
+
* (Inner) Builds the display lines for a node.
|
|
2097
|
+
* @remarks Time/Space: Proportional to the width and height of the subtrees.
|
|
2098
|
+
*/
|
|
2282
2099
|
function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
|
|
2283
2100
|
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
|
|
2284
2101
|
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
|
|
@@ -2315,22 +2132,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2315
2132
|
}
|
|
2316
2133
|
}
|
|
2317
2134
|
|
|
2318
|
-
protected _DEFAULT_NODE_CALLBACK = (node: BinaryTreeNode<K, V> | null | undefined) => (node ? node.key : undefined);
|
|
2319
|
-
|
|
2320
2135
|
/**
|
|
2321
|
-
*
|
|
2322
|
-
*
|
|
2136
|
+
* (Protected) Swaps the key/value properties of two nodes.
|
|
2137
|
+
* @remarks Time O(1)
|
|
2323
2138
|
*
|
|
2324
|
-
*
|
|
2325
|
-
* @param
|
|
2326
|
-
* `
|
|
2327
|
-
* properties, or it can be of type R.
|
|
2328
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } destNode - The `destNode` parameter in the
|
|
2329
|
-
* `_swapProperties` method represents the node or entry where the properties will be swapped with
|
|
2330
|
-
* the `srcNode`. It can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. The method ensures that
|
|
2331
|
-
* both `srcNode
|
|
2332
|
-
* @returns The `_swapProperties` method returns either the `destNode` with its key and value swapped
|
|
2333
|
-
* with the `srcNode`, or `undefined` if either `srcNode` or `destNode` is falsy.
|
|
2139
|
+
* @param srcNode - The source node.
|
|
2140
|
+
* @param destNode - The destination node.
|
|
2141
|
+
* @returns The `destNode` (now holding `srcNode`'s properties).
|
|
2334
2142
|
*/
|
|
2335
2143
|
protected _swapProperties(
|
|
2336
2144
|
srcNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -2341,12 +2149,14 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2341
2149
|
|
|
2342
2150
|
if (srcNode && destNode) {
|
|
2343
2151
|
const { key, value } = destNode;
|
|
2344
|
-
const tempNode = this.
|
|
2152
|
+
const tempNode = this._createNode(key, value); // Use a temp node to hold dest properties
|
|
2345
2153
|
|
|
2346
2154
|
if (tempNode) {
|
|
2155
|
+
// Copy src to dest
|
|
2347
2156
|
destNode.key = srcNode.key;
|
|
2348
2157
|
if (!this._isMapMode) destNode.value = srcNode.value;
|
|
2349
2158
|
|
|
2159
|
+
// Copy temp (original dest) to src
|
|
2350
2160
|
srcNode.key = tempNode.key;
|
|
2351
2161
|
if (!this._isMapMode) srcNode.value = tempNode.value;
|
|
2352
2162
|
}
|
|
@@ -2357,18 +2167,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2357
2167
|
}
|
|
2358
2168
|
|
|
2359
2169
|
/**
|
|
2360
|
-
*
|
|
2361
|
-
*
|
|
2170
|
+
* (Protected) Replaces a node in the tree with a new node, maintaining children and parent links.
|
|
2171
|
+
* @remarks Time O(1)
|
|
2362
2172
|
*
|
|
2363
|
-
*
|
|
2364
|
-
* @param
|
|
2365
|
-
*
|
|
2366
|
-
* @param {BinaryTreeNode<K, V>} newNode - The `newNode` parameter in the `_replaceNode` function represents the node
|
|
2367
|
-
* that will replace the `oldNode` in a tree data structure. This function is responsible for
|
|
2368
|
-
* updating the parent, left child, right child, and root (if necessary) references when replacing a
|
|
2369
|
-
* node in the tree.
|
|
2370
|
-
* @returns The method `_replaceNode` is returning the `newNode` that was passed as a parameter after
|
|
2371
|
-
* replacing the `oldNode` with it in the binary tree structure.
|
|
2173
|
+
* @param oldNode - The node to be replaced.
|
|
2174
|
+
* @param newNode - The node to insert.
|
|
2175
|
+
* @returns The `newNode`.
|
|
2372
2176
|
*/
|
|
2373
2177
|
protected _replaceNode(oldNode: BinaryTreeNode<K, V>, newNode: BinaryTreeNode<K, V>): BinaryTreeNode<K, V> {
|
|
2374
2178
|
if (oldNode.parent) {
|
|
@@ -2389,13 +2193,10 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2389
2193
|
}
|
|
2390
2194
|
|
|
2391
2195
|
/**
|
|
2392
|
-
*
|
|
2393
|
-
*
|
|
2196
|
+
* (Protected) Sets the root node and clears its parent reference.
|
|
2197
|
+
* @remarks Time O(1)
|
|
2394
2198
|
*
|
|
2395
|
-
*
|
|
2396
|
-
* of the previous root node.
|
|
2397
|
-
* @param v - The parameter `v` in the `_setRoot` method is of type `BinaryTreeNode<K, V> | null | undefined`, which means
|
|
2398
|
-
* it can either be an optional `BinaryTreeNode<K, V>` type or `null`.
|
|
2199
|
+
* @param v - The node to set as root.
|
|
2399
2200
|
*/
|
|
2400
2201
|
protected _setRoot(v: BinaryTreeNode<K, V> | null | undefined) {
|
|
2401
2202
|
if (v) {
|
|
@@ -2404,6 +2205,13 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2404
2205
|
this._root = v;
|
|
2405
2206
|
}
|
|
2406
2207
|
|
|
2208
|
+
/**
|
|
2209
|
+
* (Protected) Converts a key, node, entry, or predicate into a standardized predicate function.
|
|
2210
|
+
* @remarks Time O(1)
|
|
2211
|
+
*
|
|
2212
|
+
* @param keyNodeEntryOrPredicate - The item to convert.
|
|
2213
|
+
* @returns A predicate function.
|
|
2214
|
+
*/
|
|
2407
2215
|
protected _ensurePredicate(
|
|
2408
2216
|
keyNodeEntryOrPredicate:
|
|
2409
2217
|
| K
|
|
@@ -2414,18 +2222,6 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2414
2222
|
| NodePredicate<BinaryTreeNode<K, V>>
|
|
2415
2223
|
): NodePredicate<BinaryTreeNode<K, V>>;
|
|
2416
2224
|
|
|
2417
|
-
/**
|
|
2418
|
-
* Time Complexity: O(1)
|
|
2419
|
-
* Space Complexity: O(1)
|
|
2420
|
-
*
|
|
2421
|
-
* The function `_ensurePredicate` in TypeScript ensures that the input is converted into a valid
|
|
2422
|
-
* predicate function for a binary tree node.
|
|
2423
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate - The
|
|
2424
|
-
* `_ensurePredicate` method in the provided code snippet is responsible for ensuring that the input
|
|
2425
|
-
* parameter `keyNodeEntryOrPredicate` is transformed into a valid predicate function that can be
|
|
2426
|
-
* used for filtering nodes in a binary tree.
|
|
2427
|
-
* @returns A NodePredicate<BinaryTreeNode<K, V>> function is being returned.
|
|
2428
|
-
*/
|
|
2429
2225
|
protected _ensurePredicate(
|
|
2430
2226
|
keyNodeEntryOrPredicate:
|
|
2431
2227
|
| K
|
|
@@ -2451,6 +2247,7 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2451
2247
|
};
|
|
2452
2248
|
}
|
|
2453
2249
|
|
|
2250
|
+
// Assume it's a key
|
|
2454
2251
|
return (node: BinaryTreeNode<K, V> | null) => {
|
|
2455
2252
|
if (!node) return false;
|
|
2456
2253
|
return node.key === keyNodeEntryOrPredicate;
|
|
@@ -2458,33 +2255,22 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2458
2255
|
}
|
|
2459
2256
|
|
|
2460
2257
|
/**
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
2258
|
+
* (Protected) Checks if an item is a predicate function.
|
|
2259
|
+
* @remarks Time O(1)
|
|
2463
2260
|
*
|
|
2464
|
-
*
|
|
2465
|
-
* @
|
|
2466
|
-
* of value. In this context, the function `_isPredicate` is checking if `p` is a function that
|
|
2467
|
-
* satisfies the type `NodePredicate<BinaryTreeNode<K, V>>`.
|
|
2468
|
-
* @returns The function is checking if the input `p` is a function and returning a boolean value
|
|
2469
|
-
* based on that check. If `p` is a function, it will return `true`, indicating that `p` is a
|
|
2470
|
-
* predicate function for a binary tree node. If `p` is not a function, it will return `false`.
|
|
2261
|
+
* @param p - The item to check.
|
|
2262
|
+
* @returns True if it's a function.
|
|
2471
2263
|
*/
|
|
2472
2264
|
protected _isPredicate(p: any): p is NodePredicate<BinaryTreeNode<K, V>> {
|
|
2473
2265
|
return typeof p === 'function';
|
|
2474
2266
|
}
|
|
2475
2267
|
|
|
2476
2268
|
/**
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2269
|
+
* (Protected) Extracts the key from a key, node, or entry.
|
|
2270
|
+
* @remarks Time O(1)
|
|
2479
2271
|
*
|
|
2480
|
-
*
|
|
2481
|
-
*
|
|
2482
|
-
* @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `_extractKey` method you provided is a
|
|
2483
|
-
* TypeScript method that takes in a parameter `keyNodeOrEntry` of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `,
|
|
2484
|
-
* where `BTNRep` is a generic type with keys `K`, `V`, and `BinaryTreeNode<K, V>`, and `
|
|
2485
|
-
* @returns The `_extractKey` method returns the key value extracted from the `keyNodeOrEntry`
|
|
2486
|
-
* parameter. The return value can be a key value of type `K`, `null`, or `undefined`, depending on
|
|
2487
|
-
* the conditions checked in the method.
|
|
2272
|
+
* @param keyNodeOrEntry - The item.
|
|
2273
|
+
* @returns The extracted key.
|
|
2488
2274
|
*/
|
|
2489
2275
|
protected _extractKey(
|
|
2490
2276
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -2500,30 +2286,22 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2500
2286
|
}
|
|
2501
2287
|
|
|
2502
2288
|
/**
|
|
2503
|
-
*
|
|
2504
|
-
*
|
|
2289
|
+
* (Protected) Sets a value in the external store (Map mode).
|
|
2290
|
+
* @remarks Time O(1) (average for Map.set).
|
|
2505
2291
|
*
|
|
2506
|
-
*
|
|
2507
|
-
* value
|
|
2508
|
-
* @
|
|
2509
|
-
* `undefined`.
|
|
2510
|
-
* @param {V | undefined} value - The `value` parameter in the `_setValue` method can be of type `V`
|
|
2511
|
-
* or `undefined`.
|
|
2512
|
-
* @returns The method `_setValue` returns `false` if either the `key` is `null` or `undefined`, or
|
|
2513
|
-
* if the `value` is `undefined`. Otherwise, it returns the result of calling the `set` method on the
|
|
2514
|
-
* `_store` object with the `key` and `value` arguments.
|
|
2292
|
+
* @param key - The key.
|
|
2293
|
+
* @param value - The value.
|
|
2294
|
+
* @returns True if successful.
|
|
2515
2295
|
*/
|
|
2516
2296
|
protected _setValue(key: K | null | undefined, value: V | undefined) {
|
|
2517
2297
|
if (key === null || key === undefined) return false;
|
|
2518
|
-
if (value === undefined) return false;
|
|
2298
|
+
if (value === undefined) return false; // Or allow setting undefined?
|
|
2519
2299
|
return this._store.set(key, value);
|
|
2520
2300
|
}
|
|
2521
2301
|
|
|
2522
2302
|
/**
|
|
2523
|
-
*
|
|
2524
|
-
*
|
|
2525
|
-
*
|
|
2526
|
-
* The _clearNodes function sets the root node to undefined and resets the size to 0.
|
|
2303
|
+
* (Protected) Clears all nodes from the tree.
|
|
2304
|
+
* @remarks Time O(1)
|
|
2527
2305
|
*/
|
|
2528
2306
|
protected _clearNodes() {
|
|
2529
2307
|
this._setRoot(undefined);
|
|
@@ -2531,10 +2309,8 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
2531
2309
|
}
|
|
2532
2310
|
|
|
2533
2311
|
/**
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
2537
|
-
* The _clearValues function clears all values stored in the _store object.
|
|
2312
|
+
* (Protected) Clears all values from the external store.
|
|
2313
|
+
* @remarks Time O(N)
|
|
2538
2314
|
*/
|
|
2539
2315
|
protected _clearValues() {
|
|
2540
2316
|
this._store.clear();
|