min-heap-typed 1.42.6 → 1.42.7

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.
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import type {BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey} from '../../types';
10
- import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
10
+ import {BiTreeDeleteResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
11
11
  import {IBinaryTree} from '../../interfaces';
12
12
  import {trampoline} from '../../utils';
13
13
  import {Queue} from '../queue';
@@ -26,12 +26,12 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
26
26
  /**
27
27
  * The value stored in the node.
28
28
  */
29
- value: V | undefined;
29
+ value?: V;
30
30
 
31
31
  /**
32
32
  * The parent node of the current node.
33
33
  */
34
- parent: N | null | undefined;
34
+ parent?: N | null;
35
35
 
36
36
  /**
37
37
  * Creates a new instance of BinaryTreeNode.
@@ -43,7 +43,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
43
43
  this.value = value;
44
44
  }
45
45
 
46
- protected _left: N | null | undefined;
46
+ protected _left?: N | null;
47
47
 
48
48
  /**
49
49
  * Get the left child node.
@@ -63,7 +63,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
63
63
  this._left = v;
64
64
  }
65
65
 
66
- protected _right: N | null | undefined;
66
+ protected _right?: N | null;
67
67
 
68
68
  /**
69
69
  * Get the right child node.
@@ -117,13 +117,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
117
117
  * @param {BinaryTreeOptions} [options] - The options for the binary tree.
118
118
  */
119
119
  constructor(options?: BinaryTreeOptions) {
120
- if (options !== undefined) {
120
+ if (options) {
121
121
  const {iterationType = IterationType.ITERATIVE} = options;
122
122
  this.iterationType = iterationType;
123
123
  }
124
+ this._size = 0;
124
125
  }
125
126
 
126
- protected _root: N | null | undefined = undefined;
127
+ protected _root?: N | null;
127
128
 
128
129
  /**
129
130
  * Get the root node of the binary tree.
@@ -132,7 +133,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
132
133
  return this._root;
133
134
  }
134
135
 
135
- protected _size = 0;
136
+ protected _size: number;
136
137
 
137
138
  /**
138
139
  * Get the number of nodes in the binary tree.
@@ -151,22 +152,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
151
152
  return new BinaryTreeNode<V, N>(key, value) as N;
152
153
  }
153
154
 
154
- /**
155
- * Clear the binary tree, removing all nodes.
156
- */
157
- clear() {
158
- this._setRoot(undefined);
159
- this._size = 0;
160
- }
161
-
162
- /**
163
- * Check if the binary tree is empty.
164
- * @returns {boolean} - True if the binary tree is empty, false otherwise.
165
- */
166
- isEmpty(): boolean {
167
- return this.size === 0;
168
- }
169
-
170
155
  /**
171
156
  * Add a node with the given key and value to the binary tree.
172
157
  * @param {BTNKey | N | null} keyOrNode - The key or node to add to the binary tree.
@@ -192,11 +177,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
192
177
  return;
193
178
  };
194
179
 
195
- let inserted: N | null | undefined, needInsert: N | null;
180
+ let inserted: N | null | undefined, needInsert: N | null | undefined;
196
181
 
197
182
  if (keyOrNode === null) {
198
183
  needInsert = null;
199
- } else if (typeof keyOrNode === 'number') {
184
+ } else if (this.isNodeKey(keyOrNode)) {
200
185
  needInsert = this.createNode(keyOrNode, value);
201
186
  } else if (keyOrNode instanceof BinaryTreeNode) {
202
187
  needInsert = keyOrNode;
@@ -204,19 +189,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
204
189
  return;
205
190
  }
206
191
 
207
- // const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
208
- // const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
209
-
210
192
  if (this.root) {
211
- // if (existNode) {
212
- // existNode.value = value;
213
- // inserted = existNode;
214
- // } else {
215
193
  inserted = _bfs(this.root, needInsert);
216
- // }
217
194
  } else {
218
195
  this._setRoot(needInsert);
219
- if (needInsert !== null) {
196
+ if (needInsert) {
220
197
  this._size = 1;
221
198
  } else {
222
199
  this._size = 0;
@@ -236,7 +213,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
236
213
  * the value of the nodes will be `undefined`.
237
214
  * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
238
215
  */
239
- addMany(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: V[]): (N | null | undefined)[] {
216
+ addMany(keysOrNodes: (BTNKey | N |null | undefined)[], values?: (V | undefined)[]): (N | null | undefined)[] {
240
217
  // TODO not sure addMany not be run multi times
241
218
  return keysOrNodes.map((keyOrNode, i) => {
242
219
  if (keyOrNode instanceof BinaryTreeNode) {
@@ -256,50 +233,50 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
256
233
  * The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data.
257
234
  * @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either
258
235
  * `BTNKey` or `N` values.
259
- * @param {N[] | Array<V>} [data] - The `data` parameter is an optional array of values that will be assigned to
236
+ * @param {N[] | Array<V>} [values] - The `data` parameter is an optional array of values that will be assigned to
260
237
  * the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes`
261
238
  * array. Each value in the `data` array will be assigned to the
262
239
  * @returns The method is returning a boolean value.
263
240
  */
264
- refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], data?: Array<V>): boolean {
241
+ refill(keysOrNodes: (BTNKey | N | null | undefined)[], values?: (V | undefined)[]): boolean {
265
242
  this.clear();
266
- return keysOrNodes.length === this.addMany(keysOrNodes, data).length;
243
+ return keysOrNodes.length === this.addMany(keysOrNodes, values).length;
267
244
  }
268
245
 
269
- delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult<N>[];
246
+ delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BiTreeDeleteResult<N>[];
270
247
 
271
- delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BinaryTreeDeletedResult<N>[];
248
+ delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BiTreeDeleteResult<N>[];
272
249
 
273
- delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeletedResult<N>[];
250
+ delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BiTreeDeleteResult<N>[];
274
251
 
275
252
  /**
276
253
  * The `delete` function removes a node from a binary search tree and returns the deleted node along
277
254
  * with the parent node that needs to be balanced.
278
255
  * a key (`BTNKey`). If it is a key, the function will find the corresponding node in the
279
256
  * binary tree.
280
- * @returns an array of `BinaryTreeDeletedResult<N>` objects.
257
+ * @returns an array of `BiTreeDeleteResult<N>` objects.
281
258
  * @param {ReturnType<C>} identifier - The `identifier` parameter is either a
282
259
  * `BTNKey` or a generic type `N`. It represents the property of the node that we are
283
260
  * searching for. It can be a specific key value or any other property of the node.
284
261
  * @param callback - The `callback` parameter is a function that takes a node as input and returns a
285
262
  * value. This value is compared with the `identifier` parameter to determine if the node should be
286
263
  * included in the result. The `callback` parameter has a default value of
287
- * `this.defaultOneParamCallback`, which
264
+ * `this._defaultOneParamCallback`, which
288
265
  */
289
266
  delete<C extends BTNCallback<N>>(
290
267
  identifier: ReturnType<C> | null | undefined,
291
- callback: C = this.defaultOneParamCallback as C
292
- ): BinaryTreeDeletedResult<N>[] {
293
- const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
294
- if (!this.root) return bstDeletedResult;
268
+ callback: C = this._defaultOneParamCallback as C
269
+ ): BiTreeDeleteResult<N>[] {
270
+ const deletedResult: BiTreeDeleteResult<N>[] = [];
271
+ if (!this.root) return deletedResult;
295
272
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
296
273
 
297
274
  const curr = this.getNode(identifier, callback);
298
- if (!curr) return bstDeletedResult;
275
+ if (!curr) return deletedResult;
299
276
 
300
277
  const parent: N | null | undefined = curr?.parent ? curr.parent : null;
301
- let needBalanced: N | null | undefined = null,
302
- orgCurrent = curr;
278
+ let needBalanced: N | null | undefined = undefined;
279
+ let orgCurrent: N | undefined = curr;
303
280
 
304
281
  if (!curr.left) {
305
282
  if (!parent) {
@@ -329,8 +306,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
329
306
  }
330
307
  this._size = this.size - 1;
331
308
 
332
- bstDeletedResult.push({deleted: orgCurrent, needBalanced});
333
- return bstDeletedResult;
309
+ deletedResult.push({deleted: orgCurrent, needBalanced});
310
+ return deletedResult;
334
311
  }
335
312
 
336
313
  /**
@@ -346,8 +323,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
346
323
  * @returns the depth of the `distNode` relative to the `beginRoot`.
347
324
  */
348
325
  getDepth(distNode: BTNKey | N | null | undefined, beginRoot: BTNKey | N | null | undefined = this.root): number {
349
- if (typeof distNode === 'number') distNode = this.getNode(distNode);
350
- if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
326
+ distNode = this.ensureNotKey(distNode);
327
+ beginRoot = this.ensureNotKey(beginRoot);
351
328
  let depth = 0;
352
329
  while (distNode?.parent) {
353
330
  if (distNode === beginRoot) {
@@ -372,7 +349,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
372
349
  * @returns the height of the binary tree.
373
350
  */
374
351
  getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
375
- if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
352
+ beginRoot = this.ensureNotKey(beginRoot);
376
353
  if (!beginRoot) return -1;
377
354
 
378
355
  if (iterationType === IterationType.RECURSIVE) {
@@ -395,14 +372,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
395
372
  while (stack.length > 0) {
396
373
  const {node, depth} = stack.pop()!;
397
374
 
398
- if (node.left) {
399
- stack.push({node: node.left, depth: depth + 1});
400
- }
401
-
402
- if (node.right) {
403
- stack.push({node: node.right, depth: depth + 1});
404
- }
405
-
375
+ if (node.left) stack.push({node: node.left, depth: depth + 1});
376
+ if (node.right) stack.push({node: node.right, depth: depth + 1});
377
+
406
378
  maxHeight = Math.max(maxHeight, depth);
407
379
  }
408
380
 
@@ -420,9 +392,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
420
392
  * to calculate the minimum height of a binary tree. It can have two possible values:
421
393
  * @returns The function `getMinHeight` returns the minimum height of a binary tree.
422
394
  */
423
- getMinHeight(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): number {
395
+ getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
396
+ beginRoot = this.ensureNotKey(beginRoot);
424
397
  if (!beginRoot) return -1;
425
-
398
+
426
399
  if (iterationType === IterationType.RECURSIVE) {
427
400
  const _getMinHeight = (cur: N | null | undefined): number => {
428
401
  if (!cur) return 0;
@@ -469,7 +442,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
469
442
  * either be of type `N` (representing a node in a tree) or `null` (representing an empty tree).
470
443
  * @returns The method is returning a boolean value.
471
444
  */
472
- isPerfectlyBalanced(beginRoot: N | null | undefined = this.root): boolean {
445
+ isPerfectlyBalanced(beginRoot: BTNKey | N | null | undefined = this.root): boolean {
473
446
  return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
474
447
  }
475
448
 
@@ -477,7 +450,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
477
450
  identifier: BTNKey,
478
451
  callback?: C,
479
452
  onlyOne?: boolean,
480
- beginRoot?: N | null | undefined,
453
+ beginRoot?: BTNKey | N | null | undefined,
481
454
  iterationType?: IterationType
482
455
  ): N[];
483
456
 
@@ -485,7 +458,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
485
458
  identifier: N | null | undefined,
486
459
  callback?: C,
487
460
  onlyOne?: boolean,
488
- beginRoot?: N | null | undefined,
461
+ beginRoot?: BTNKey | N | null | undefined,
489
462
  iterationType?: IterationType
490
463
  ): N[];
491
464
 
@@ -493,7 +466,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
493
466
  identifier: ReturnType<C>,
494
467
  callback: C,
495
468
  onlyOne?: boolean,
496
- beginRoot?: N | null | undefined,
469
+ beginRoot?: BTNKey | N | null | undefined,
497
470
  iterationType?: IterationType
498
471
  ): N[];
499
472
 
@@ -506,7 +479,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
506
479
  * @param callback - The `callback` parameter is a function that takes a node as input and returns a
507
480
  * value. This value is compared with the `identifier` parameter to determine if the node should be
508
481
  * included in the result. The `callback` parameter has a default value of
509
- * `this.defaultOneParamCallback`, which
482
+ * `this._defaultOneParamCallback`, which
510
483
  * @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the
511
484
  * first node that matches the identifier. If set to true, the function will return an array with
512
485
  * only one element (or an empty array if no matching node is found). If set to false (default), the
@@ -520,13 +493,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
520
493
  */
521
494
  getNodes<C extends BTNCallback<N>>(
522
495
  identifier: ReturnType<C> | null | undefined,
523
- callback: C = this.defaultOneParamCallback as C,
496
+ callback: C = this._defaultOneParamCallback as C,
524
497
  onlyOne = false,
525
- beginRoot: N | null | undefined = this.root,
498
+ beginRoot: BTNKey | N | null | undefined = this.root,
526
499
  iterationType = this.iterationType
527
500
  ): N[] {
528
501
  if (!beginRoot) return [];
529
502
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
503
+ beginRoot = this.ensureNotKey(beginRoot);
504
+ if (!beginRoot) return [];
505
+
530
506
  const ans: N[] = [];
531
507
 
532
508
  if (iterationType === IterationType.RECURSIVE) {
@@ -562,21 +538,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
562
538
  has<C extends BTNCallback<N, BTNKey>>(
563
539
  identifier: BTNKey,
564
540
  callback?: C,
565
- beginRoot?: N | null | undefined,
541
+ beginRoot?: BTNKey | N | null | undefined,
566
542
  iterationType?: IterationType
567
543
  ): boolean;
568
544
 
569
545
  has<C extends BTNCallback<N, N>>(
570
546
  identifier: N | null | undefined,
571
547
  callback?: C,
572
- beginRoot?: N | null | undefined,
548
+ beginRoot?: BTNKey | N | null | undefined,
573
549
  iterationType?: IterationType
574
550
  ): boolean;
575
551
 
576
552
  has<C extends BTNCallback<N>>(
577
553
  identifier: ReturnType<C> | null | undefined,
578
554
  callback: C,
579
- beginRoot?: N | null | undefined,
555
+ beginRoot?: BTNKey | N | null | undefined,
580
556
  iterationType?: IterationType
581
557
  ): boolean;
582
558
 
@@ -588,7 +564,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
588
564
  * @param callback - The `callback` parameter is a function that is used to determine whether a node
589
565
  * matches the desired criteria. It takes a node as input and returns a boolean value indicating
590
566
  * whether the node matches the criteria or not. The default callback function
591
- * `this.defaultOneParamCallback` is used if no callback function is
567
+ * `this._defaultOneParamCallback` is used if no callback function is
592
568
  * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
593
569
  * the node from which the search should begin. By default, it is set to `this.root`, which means the
594
570
  * search will start from the root node of the binary tree. However, you can provide a different node
@@ -599,8 +575,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
599
575
  */
600
576
  has<C extends BTNCallback<N>>(
601
577
  identifier: ReturnType<C> | null | undefined,
602
- callback: C = this.defaultOneParamCallback as C,
603
- beginRoot = this.root,
578
+ callback: C = this._defaultOneParamCallback as C,
579
+ beginRoot: BTNKey | N | null | undefined = this.root,
604
580
  iterationType = this.iterationType
605
581
  ): boolean {
606
582
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
@@ -611,21 +587,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
611
587
  getNode<C extends BTNCallback<N, BTNKey>>(
612
588
  identifier: BTNKey,
613
589
  callback?: C,
614
- beginRoot?: N | null | undefined,
590
+ beginRoot?: BTNKey | N | null | undefined,
615
591
  iterationType?: IterationType
616
592
  ): N | null | undefined;
617
593
 
618
594
  getNode<C extends BTNCallback<N, N>>(
619
595
  identifier: N | null | undefined,
620
596
  callback?: C,
621
- beginRoot?: N | null | undefined,
597
+ beginRoot?: BTNKey | N | null | undefined,
622
598
  iterationType?: IterationType
623
599
  ): N | null | undefined;
624
600
 
625
601
  getNode<C extends BTNCallback<N>>(
626
602
  identifier: ReturnType<C>,
627
603
  callback: C,
628
- beginRoot?: N | null | undefined,
604
+ beginRoot?: BTNKey | N | null | undefined,
629
605
  iterationType?: IterationType
630
606
  ): N | null | undefined;
631
607
 
@@ -637,7 +613,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
637
613
  * @param callback - The `callback` parameter is a function that is used to determine whether a node
638
614
  * matches the desired criteria. It takes a node as input and returns a boolean value indicating
639
615
  * whether the node matches the criteria or not. The default callback function
640
- * (`this.defaultOneParamCallback`) is used if no callback function is
616
+ * (`this._defaultOneParamCallback`) is used if no callback function is
641
617
  * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
642
618
  * the root node from which the search should begin.
643
619
  * @param iterationType - The `iterationType` parameter specifies the type of iteration to be
@@ -646,8 +622,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
646
622
  */
647
623
  getNode<C extends BTNCallback<N>>(
648
624
  identifier: ReturnType<C> | null | undefined,
649
- callback: C = this.defaultOneParamCallback as C,
650
- beginRoot = this.root,
625
+ callback: C = this._defaultOneParamCallback as C,
626
+ beginRoot: BTNKey | N | null | undefined = this.root,
651
627
  iterationType = this.iterationType
652
628
  ): N | null | undefined {
653
629
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
@@ -655,24 +631,75 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
655
631
  return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
656
632
  }
657
633
 
634
+ /**
635
+ * The function `getNodeByKey` searches for a node in a binary tree by its key, using either
636
+ * recursive or iterative iteration.
637
+ * @param {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree.
638
+ * It is used to find the node with the matching key value.
639
+ * @param iterationType - The `iterationType` parameter is used to determine whether the search for
640
+ * the node with the given key should be performed iteratively or recursively. It has two possible
641
+ * values:
642
+ * @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
643
+ * found in the binary tree. If no node is found, it returns `undefined`.
644
+ */
645
+ getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
646
+ if (!this.root) return undefined;
647
+ if (iterationType === IterationType.RECURSIVE) {
648
+ const _dfs = (cur: N): N | undefined => {
649
+ if (cur.key === key) return cur;
650
+
651
+ if (!cur.left && !cur.right) return;
652
+ if (cur.left) return _dfs(cur.left);
653
+ if (cur.right) return _dfs(cur.right);
654
+ };
655
+
656
+ return _dfs(this.root);
657
+ } else {
658
+ const queue = new Queue<N>([this.root]);
659
+ while (queue.size > 0) {
660
+ const cur = queue.shift();
661
+ if (cur) {
662
+ if (cur.key === key) return cur;
663
+ cur.left && queue.push(cur.left);
664
+ cur.right && queue.push(cur.right);
665
+ }
666
+ }
667
+ }
668
+ }
669
+
670
+ /**
671
+ * The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node
672
+ * key, otherwise it returns the key itself.
673
+ * @param {BTNKey | N | null | undefined} key - The `key` parameter can be of type `BTNKey`, `N`,
674
+ * `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
675
+ * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
676
+ * type of iteration to be used when searching for a node by key. It has a default value of
677
+ * `IterationType.ITERATIVE`.
678
+ * @returns either the node corresponding to the given key if it is a valid node key, or the key
679
+ * itself if it is not a valid node key.
680
+ */
681
+ ensureNotKey(key: BTNKey | N | null | undefined, iterationType = IterationType.ITERATIVE): N | null | undefined {
682
+ return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
683
+ }
684
+
658
685
  get<C extends BTNCallback<N, BTNKey>>(
659
686
  identifier: BTNKey,
660
687
  callback?: C,
661
- beginRoot?: N | null | undefined,
688
+ beginRoot?: BTNKey | N | null | undefined,
662
689
  iterationType?: IterationType
663
690
  ): V | undefined;
664
691
 
665
692
  get<C extends BTNCallback<N, N>>(
666
693
  identifier: N | null | undefined,
667
694
  callback?: C,
668
- beginRoot?: N | null | undefined,
695
+ beginRoot?: BTNKey | N | null | undefined,
669
696
  iterationType?: IterationType
670
697
  ): V | undefined;
671
698
 
672
699
  get<C extends BTNCallback<N>>(
673
700
  identifier: ReturnType<C>,
674
701
  callback: C,
675
- beginRoot?: N | null | undefined,
702
+ beginRoot?: BTNKey | N | null | undefined,
676
703
  iterationType?: IterationType
677
704
  ): V | undefined;
678
705
 
@@ -684,7 +711,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
684
711
  * @param callback - The `callback` parameter is a function that is used to determine whether a node
685
712
  * matches the desired criteria. It takes a node as input and returns a boolean value indicating
686
713
  * whether the node matches the criteria or not. The default callback function
687
- * (`this.defaultOneParamCallback`) is used if no callback function is
714
+ * (`this._defaultOneParamCallback`) is used if no callback function is
688
715
  * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
689
716
  * the root node from which the search should begin.
690
717
  * @param iterationType - The `iterationType` parameter specifies the type of iteration to be
@@ -693,15 +720,31 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
693
720
  */
694
721
  get<C extends BTNCallback<N>>(
695
722
  identifier: ReturnType<C> | null | undefined,
696
- callback: C = this.defaultOneParamCallback as C,
697
- beginRoot = this.root,
723
+ callback: C = this._defaultOneParamCallback as C,
724
+ beginRoot:BTNKey | N | null | undefined = this.root,
698
725
  iterationType = this.iterationType
699
726
  ): V | undefined {
700
727
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
701
728
 
702
729
  return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
703
730
  }
731
+
732
+ /**
733
+ * Clear the binary tree, removing all nodes.
734
+ */
735
+ clear() {
736
+ this._setRoot(undefined);
737
+ this._size = 0;
738
+ }
704
739
 
740
+ /**
741
+ * Check if the binary tree is empty.
742
+ * @returns {boolean} - True if the binary tree is empty, false otherwise.
743
+ */
744
+ isEmpty(): boolean {
745
+ return this.size === 0;
746
+ }
747
+
705
748
  /**
706
749
  * The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
707
750
  * up to the root node, with the option to reverse the order of the nodes.
@@ -712,9 +755,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
712
755
  * reversed before returning it. If `isReverse` is set to `false` or not provided, the path will
713
756
  * @returns The function `getPathToRoot` returns an array of type `N[]`.
714
757
  */
715
- getPathToRoot(beginRoot: N, isReverse = true): N[] {
758
+ getPathToRoot(beginRoot: BTNKey | N | null | undefined, isReverse = true): N[] {
716
759
  // TODO to support get path through passing key
717
760
  const result: N[] = [];
761
+ beginRoot = this.ensureNotKey(beginRoot);
762
+
763
+ if (!beginRoot) return result;
764
+
718
765
  while (beginRoot.parent) {
719
766
  // Array.push + Array.reverse is more efficient than Array.unshift
720
767
  // TODO may consider using Deque, so far this is not the performance bottleneck
@@ -737,13 +784,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
737
784
  * no leftmost node, it returns `null`.
738
785
  */
739
786
  getLeftMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
740
- if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
787
+ beginRoot = this.ensureNotKey(beginRoot);
741
788
 
742
789
  if (!beginRoot) return beginRoot;
743
790
 
744
791
  if (iterationType === IterationType.RECURSIVE) {
745
792
  const _traverse = (cur: N): N => {
746
- if (!cur.left) return cur;
793
+ if (!this.isRealNode(cur.left)) return cur;
747
794
  return _traverse(cur.left);
748
795
  };
749
796
 
@@ -751,7 +798,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
751
798
  } else {
752
799
  // Indirect implementation of iteration using tail recursion optimization
753
800
  const _traverse = trampoline((cur: N) => {
754
- if (!cur.left) return cur;
801
+ if (!this.isRealNode(cur.left)) return cur;
755
802
  return _traverse.cont(cur.left);
756
803
  });
757
804
 
@@ -770,13 +817,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
770
817
  * @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If the
771
818
  * `beginRoot` parameter is `null`, it returns `null`.
772
819
  */
773
- getRightMost(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
820
+ getRightMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
774
821
  // TODO support get right most by passing key in
822
+ beginRoot = this.ensureNotKey(beginRoot);
775
823
  if (!beginRoot) return beginRoot;
776
824
 
777
825
  if (iterationType === IterationType.RECURSIVE) {
778
826
  const _traverse = (cur: N): N => {
779
- if (!cur.right) return cur;
827
+ if (!this.isRealNode(cur.right)) return cur;
780
828
  return _traverse(cur.right);
781
829
  };
782
830
 
@@ -784,7 +832,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
784
832
  } else {
785
833
  // Indirect implementation of iteration using tail recursion optimization
786
834
  const _traverse = trampoline((cur: N) => {
787
- if (!cur.right) return cur;
835
+ if (!this.isRealNode(cur.right)) return cur;
788
836
  return _traverse.cont(cur.right);
789
837
  });
790
838
 
@@ -801,8 +849,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
801
849
  * possible values:
802
850
  * @returns The function `isSubtreeBST` returns a boolean value.
803
851
  */
804
- isSubtreeBST(beginRoot: N | null | undefined, iterationType = this.iterationType): boolean {
852
+ isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
805
853
  // TODO there is a bug
854
+ beginRoot = this.ensureNotKey(beginRoot);
806
855
  if (!beginRoot) return true;
807
856
 
808
857
  if (iterationType === IterationType.RECURSIVE) {
@@ -881,12 +930,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
881
930
  * @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
882
931
  */
883
932
  subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
884
- callback: C = this.defaultOneParamCallback as C,
933
+ callback: C = this._defaultOneParamCallback as C,
885
934
  beginRoot: BTNKey | N | null | undefined = this.root,
886
935
  iterationType = this.iterationType,
887
936
  includeNull = false
888
937
  ): ReturnType<C>[] {
889
- if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
938
+ beginRoot = this.ensureNotKey(beginRoot);
890
939
 
891
940
  const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
892
941
  if (!beginRoot) return ans;
@@ -926,22 +975,48 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
926
975
  return ans;
927
976
  }
928
977
 
929
- isNode(node: any): node is N {
978
+ /**
979
+ * The function checks if a given node is a real node by verifying if it is an instance of
980
+ * BinaryTreeNode and its key is not NaN.
981
+ * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
982
+ * @returns a boolean value.
983
+ */
984
+ isRealNode(node: any): node is N {
930
985
  return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
931
986
  }
932
987
 
988
+ /**
989
+ * The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN.
990
+ * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
991
+ * @returns a boolean value.
992
+ */
933
993
  isNIL(node: any) {
934
994
  return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
935
995
  }
936
996
 
997
+ /**
998
+ * The function checks if a given node is a real node or null.
999
+ * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
1000
+ * @returns a boolean value.
1001
+ */
937
1002
  isNodeOrNull(node: any): node is (N | null){
938
- return this.isNode(node) || node === null;
1003
+ return this.isRealNode(node) || node === null;
1004
+ }
1005
+
1006
+ /**
1007
+ * The function "isNodeKey" checks if a potential key is a number.
1008
+ * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
1009
+ * data type.
1010
+ * @returns a boolean value indicating whether the potentialKey is of type number or not.
1011
+ */
1012
+ isNodeKey(potentialKey: any) : potentialKey is number {
1013
+ return typeof potentialKey === 'number';
939
1014
  }
940
1015
 
941
1016
  dfs<C extends BTNCallback<N>>(
942
1017
  callback?: C,
943
1018
  pattern?: DFSOrderPattern,
944
- beginRoot?: N | null | undefined,
1019
+ beginRoot?: BTNKey | N | null | undefined,
945
1020
  iterationType?: IterationType,
946
1021
  includeNull?: false
947
1022
  ): ReturnType<C>[];
@@ -949,7 +1024,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
949
1024
  dfs<C extends BTNCallback<N>>(
950
1025
  callback?: C,
951
1026
  pattern?: DFSOrderPattern,
952
- beginRoot?: N | null | undefined,
1027
+ beginRoot?: BTNKey | N | null | undefined,
953
1028
  iterationType?: IterationType,
954
1029
  includeNull?: undefined
955
1030
  ): ReturnType<C>[];
@@ -957,7 +1032,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
957
1032
  dfs<C extends BTNCallback<N | null | undefined>>(
958
1033
  callback?: C,
959
1034
  pattern?: DFSOrderPattern,
960
- beginRoot?: N | null | undefined,
1035
+ beginRoot?: BTNKey | N | null | undefined,
961
1036
  iterationType?: IterationType,
962
1037
  includeNull?: true
963
1038
  ): ReturnType<C>[];
@@ -967,7 +1042,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
967
1042
  * function on each node according to a specified order pattern.
968
1043
  * @param callback - The `callback` parameter is a function that will be called on each node during
969
1044
  * the depth-first search traversal. It takes a node as input and returns a value. The default value
970
- * is `this.defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
1045
+ * is `this._defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
971
1046
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
972
1047
  * nodes are visited during the depth-first search. There are three possible values for `pattern`:
973
1048
  * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
@@ -979,12 +1054,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
979
1054
  * @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
980
1055
  */
981
1056
  dfs<C extends BTNCallback<N | null | undefined>>(
982
- callback: C = this.defaultOneParamCallback as C,
1057
+ callback: C = this._defaultOneParamCallback as C,
983
1058
  pattern: DFSOrderPattern = 'in',
984
- beginRoot: N | null | undefined = this.root,
1059
+ beginRoot: BTNKey | N | null | undefined = this.root,
985
1060
  iterationType: IterationType = IterationType.ITERATIVE,
986
1061
  includeNull = false
987
1062
  ): ReturnType<C>[] {
1063
+
1064
+ beginRoot = this.ensureNotKey(beginRoot);
988
1065
  if (!beginRoot) return [];
989
1066
  const ans: ReturnType<C>[] = [];
990
1067
  if (iterationType === IterationType.RECURSIVE) {
@@ -997,7 +1074,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
997
1074
  if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
998
1075
  } else {
999
1076
  if (node && node.left) _traverse(node.left);
1000
- this.isNode(node) && ans.push(callback(node));
1077
+ this.isRealNode(node) && ans.push(callback(node));
1001
1078
  if (node && node.right) _traverse(node.right);
1002
1079
  }
1003
1080
  break;
@@ -1007,7 +1084,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1007
1084
  if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
1008
1085
  if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
1009
1086
  } else {
1010
- this.isNode(node) && ans.push(callback(node));
1087
+ this.isRealNode(node) && ans.push(callback(node));
1011
1088
  if (node && node.left) _traverse(node.left);
1012
1089
  if (node && node.right) _traverse(node.right);
1013
1090
  }
@@ -1020,7 +1097,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1020
1097
  } else {
1021
1098
  if (node && node.left) _traverse(node.left);
1022
1099
  if (node && node.right) _traverse(node.right);
1023
- this.isNode(node) && ans.push(callback(node));
1100
+ this.isRealNode(node) && ans.push(callback(node));
1024
1101
  }
1025
1102
 
1026
1103
  break;
@@ -1074,21 +1151,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1074
1151
 
1075
1152
  bfs<C extends BTNCallback<N>>(
1076
1153
  callback?: C,
1077
- beginRoot?: N | null | undefined,
1154
+ beginRoot?: BTNKey | N | null | undefined,
1078
1155
  iterationType?: IterationType,
1079
1156
  includeNull?: false
1080
1157
  ): ReturnType<C>[];
1081
1158
 
1082
1159
  bfs<C extends BTNCallback<N>>(
1083
1160
  callback?: C,
1084
- beginRoot?: N | null | undefined,
1161
+ beginRoot?: BTNKey | N | null | undefined,
1085
1162
  iterationType?: IterationType,
1086
1163
  includeNull?: undefined
1087
1164
  ): ReturnType<C>[];
1088
1165
 
1089
1166
  bfs<C extends BTNCallback<N | null | undefined>>(
1090
1167
  callback?: C,
1091
- beginRoot?: N | null | undefined,
1168
+ beginRoot?: BTNKey | N | null | undefined,
1092
1169
  iterationType?: IterationType,
1093
1170
  includeNull?: true
1094
1171
  ): ReturnType<C>[];
@@ -1098,7 +1175,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1098
1175
  * function on each node.
1099
1176
  * @param callback - The `callback` parameter is a function that will be called for each node in the
1100
1177
  * breadth-first search. It takes a node of type `N` as its argument and returns a value of type
1101
- * `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this.defaultOneParamCallback
1178
+ * `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this._defaultOneParamCallback
1102
1179
  * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
1103
1180
  * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
1104
1181
  * will not be performed and an empty array will be returned.
@@ -1108,11 +1185,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1108
1185
  * @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
1109
1186
  */
1110
1187
  bfs<C extends BTNCallback<N | null | undefined>>(
1111
- callback: C = this.defaultOneParamCallback as C,
1112
- beginRoot: N | null | undefined = this.root,
1188
+ callback: C = this._defaultOneParamCallback as C,
1189
+ beginRoot: BTNKey | N | null | undefined = this.root,
1113
1190
  iterationType = this.iterationType,
1114
1191
  includeNull = false
1115
1192
  ): ReturnType<C>[] {
1193
+ beginRoot = this.ensureNotKey(beginRoot);
1116
1194
  if (!beginRoot) return [];
1117
1195
 
1118
1196
  const ans: ReturnType<BTNCallback<N>>[] = [];
@@ -1162,21 +1240,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1162
1240
 
1163
1241
  listLevels<C extends BTNCallback<N>>(
1164
1242
  callback?: C,
1165
- beginRoot?: N | null | undefined,
1243
+ beginRoot?: BTNKey | N | null | undefined,
1166
1244
  iterationType?: IterationType,
1167
1245
  includeNull?: false
1168
1246
  ): ReturnType<C>[][];
1169
1247
 
1170
1248
  listLevels<C extends BTNCallback<N>>(
1171
1249
  callback?: C,
1172
- beginRoot?: N | null | undefined,
1250
+ beginRoot?: BTNKey | N | null | undefined,
1173
1251
  iterationType?: IterationType,
1174
1252
  includeNull?: undefined
1175
1253
  ): ReturnType<C>[][];
1176
1254
 
1177
1255
  listLevels<C extends BTNCallback<N | null | undefined>>(
1178
1256
  callback?: C,
1179
- beginRoot?: N | null | undefined,
1257
+ beginRoot?: BTNKey | N | null | undefined,
1180
1258
  iterationType?: IterationType,
1181
1259
  includeNull?: true
1182
1260
  ): ReturnType<C>[][];
@@ -1198,13 +1276,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1198
1276
  * function `C` applied to the nodes at that level.
1199
1277
  */
1200
1278
  listLevels<C extends BTNCallback<N | null | undefined>>(
1201
- callback: C = this.defaultOneParamCallback as C,
1202
- beginRoot: N | null | undefined = this.root,
1279
+ callback: C = this._defaultOneParamCallback as C,
1280
+ beginRoot: BTNKey | N | null | undefined = this.root,
1203
1281
  iterationType = this.iterationType,
1204
1282
  includeNull = false
1205
1283
  ): ReturnType<C>[][] {
1206
- if (!beginRoot) return [];
1284
+ beginRoot = this.ensureNotKey(beginRoot);
1207
1285
  const levelsNodes: ReturnType<C>[][] = [];
1286
+ if (!beginRoot) return levelsNodes;
1208
1287
 
1209
1288
  if (iterationType === IterationType.RECURSIVE) {
1210
1289
  const _recursive = (node: N | null | undefined, level: number) => {
@@ -1243,15 +1322,20 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1243
1322
  return levelsNodes;
1244
1323
  }
1245
1324
 
1325
+ getPredecessor(node: N ): N
1326
+
1246
1327
  /**
1247
1328
  * The function returns the predecessor node of a given node in a binary tree.
1248
1329
  * @param {N} node - The parameter "node" represents a node in a binary tree.
1249
1330
  * @returns The function `getPredecessor` returns the predecessor node of the given node `node`.
1250
1331
  */
1251
- getPredecessor(node: N): N {
1332
+ getPredecessor(node: BTNKey | N | null | undefined): N | undefined{
1333
+ node = this.ensureNotKey(node);
1334
+ if (!this.isRealNode(node)) return undefined;
1335
+
1252
1336
  if (node.left) {
1253
1337
  let predecessor: N | null | undefined = node.left;
1254
- while (!predecessor || (predecessor.right && predecessor.right !== node)) {
1338
+ while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
1255
1339
  if (predecessor) {
1256
1340
  predecessor = predecessor.right;
1257
1341
  }
@@ -1269,7 +1353,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1269
1353
  * @returns The function `getSuccessor` returns a value of type `N` (the successor node), or `null`
1270
1354
  * if there is no successor, or `undefined` if the input `x` is `undefined`.
1271
1355
  */
1272
- getSuccessor(x: N): N | null | undefined {
1356
+ getSuccessor(x?: BTNKey | N | null): N | null | undefined {
1357
+ x = this.ensureNotKey(x);
1358
+ if (!x) return undefined;
1359
+
1273
1360
  if (x.right) {
1274
1361
  return this.getLeftMost(x.right);
1275
1362
  }
@@ -1287,7 +1374,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1287
1374
  * algorithm and returns an array of values obtained by applying a callback function to each node.
1288
1375
  * @param callback - The `callback` parameter is a function that will be called on each node in the
1289
1376
  * tree. It takes a node of type `N` as input and returns a value of type `ReturnType<BTNCallback<N>>`. The
1290
- * default value for this parameter is `this.defaultOneParamCallback`.
1377
+ * default value for this parameter is `this._defaultOneParamCallback`.
1291
1378
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
1292
1379
  * determines the order in which the nodes of a binary tree are traversed. It can have one of the
1293
1380
  * following values:
@@ -1297,10 +1384,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1297
1384
  * @returns The `morris` function returns an array of `ReturnType<BTNCallback<N>>` values.
1298
1385
  */
1299
1386
  morris<C extends BTNCallback<N>>(
1300
- callback: C = this.defaultOneParamCallback as C,
1387
+ callback: C = this._defaultOneParamCallback as C,
1301
1388
  pattern: DFSOrderPattern = 'in',
1302
- beginRoot: N | null | undefined = this.root
1389
+ beginRoot: BTNKey | N | null | undefined = this.root
1303
1390
  ): ReturnType<C>[] {
1391
+ beginRoot = this.ensureNotKey(beginRoot);
1304
1392
  if (beginRoot === null) return [];
1305
1393
  const ans: ReturnType<BTNCallback<N>>[] = [];
1306
1394
 
@@ -1425,7 +1513,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1425
1513
  }
1426
1514
  }
1427
1515
 
1428
- protected defaultOneParamCallback = (node: N) => node.key;
1516
+ protected _defaultOneParamCallback = (node: N) => node.key;
1429
1517
 
1430
1518
  /**
1431
1519
  * Swap the data of two nodes in the binary tree.
@@ -1433,19 +1521,26 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1433
1521
  * @param {N} destNode - The destination node to swap.
1434
1522
  * @returns {N} - The destination node after the swap.
1435
1523
  */
1436
- protected _swap(srcNode: N, destNode: N): N {
1437
- const {key, value} = destNode;
1438
- const tempNode = this.createNode(key, value);
1524
+ protected _swap(srcNode: BTNKey | N | null | undefined, destNode:BTNKey | N | null | undefined): N | undefined{
1525
+ srcNode = this.ensureNotKey(srcNode);
1526
+ destNode = this.ensureNotKey(destNode);
1439
1527
 
1440
- if (tempNode) {
1441
- destNode.key = srcNode.key;
1442
- destNode.value = srcNode.value;
1528
+ if (srcNode && destNode) {
1529
+ const {key, value} = destNode;
1530
+ const tempNode = this.createNode(key, value);
1443
1531
 
1444
- srcNode.key = tempNode.key;
1445
- srcNode.value = tempNode.value;
1532
+ if (tempNode) {
1533
+ destNode.key = srcNode.key;
1534
+ destNode.value = srcNode.value;
1535
+
1536
+ srcNode.key = tempNode.key;
1537
+ srcNode.value = tempNode.value;
1538
+ }
1539
+
1540
+ return destNode;
1446
1541
  }
1542
+ return undefined;
1447
1543
 
1448
- return destNode;
1449
1544
  }
1450
1545
 
1451
1546
  /**
@@ -1459,7 +1554,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1459
1554
  * the binary tree. If neither the left nor right child is available, the function returns undefined.
1460
1555
  * If the parent node is null, the function also returns undefined.
1461
1556
  */
1462
- protected _addTo(newNode: N | null | undefined, parent: N): N | null | undefined {
1557
+ protected _addTo(newNode: N | null | undefined, parent: BTNKey | N | null | undefined): N | null | undefined {
1558
+ if (this.isNodeKey(parent)) parent = this.getNode(parent);
1559
+
1463
1560
  if (parent) {
1464
1561
  // When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
1465
1562
  // In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."
@@ -1496,7 +1593,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1496
1593
  this._root = v;
1497
1594
  }
1498
1595
 
1499
- print(beginRoot: N | null | undefined = this.root) {
1596
+ /**
1597
+ * The `print` function is used to display a binary tree structure in a visually appealing way.
1598
+ * @param {N | null | undefined} root - The `root` parameter in the `print` function represents the
1599
+ * root node of a binary tree. It can have one of the following types: `BTNKey`, `N`, `null`, or
1600
+ * `undefined`. The default value is `this.root`, which suggests that `this.root` is the
1601
+ */
1602
+ print(beginRoot: BTNKey | N | null | undefined = this.root): void {
1603
+ beginRoot = this.ensureNotKey(beginRoot);
1604
+ if (!beginRoot) return;
1605
+
1500
1606
  const display = (root: N | null | undefined): void => {
1501
1607
  const [lines, , ,] = _displayAux(root);
1502
1608
  for (const line of lines) {