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