min-heap-typed 1.42.2 → 1.42.4

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.
@@ -108,7 +108,8 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
108
108
  * @template N - The type of the binary tree's nodes.
109
109
  */
110
110
  export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
111
- implements IBinaryTree<V, N> {
111
+ implements IBinaryTree<V, N>
112
+ {
112
113
  iterationType: IterationType = IterationType.ITERATIVE;
113
114
 
114
115
  /**
@@ -122,12 +123,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
122
123
  }
123
124
  }
124
125
 
125
- protected _root: N | null = null;
126
+ protected _root: N | null | undefined = undefined;
126
127
 
127
128
  /**
128
129
  * Get the root node of the binary tree.
129
130
  */
130
- get root(): N | null {
131
+ get root(): N | null | undefined {
131
132
  return this._root;
132
133
  }
133
134
 
@@ -140,8 +141,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
140
141
  return this._size;
141
142
  }
142
143
 
143
- protected defaultOneParamCallback = (node: N) => node.key;
144
-
145
144
  /**
146
145
  * Creates a new instance of BinaryTreeNode with the given key and value.
147
146
  * @param {BTNKey} key - The key for the new node.
@@ -156,7 +155,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
156
155
  * Clear the binary tree, removing all nodes.
157
156
  */
158
157
  clear() {
159
- this._setRoot(null);
158
+ this._setRoot(undefined);
160
159
  this._size = 0;
161
160
  }
162
161
 
@@ -174,7 +173,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
174
173
  * @param {V} value - The value for the new node (optional).
175
174
  * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed.
176
175
  */
177
- add(keyOrNode: BTNKey | N | null, value?: V): N | null | undefined {
176
+ add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | null | undefined {
178
177
  const _bfs = (root: N, newNode: N | null): N | undefined | null => {
179
178
  const queue = new Queue<N | null>([root]);
180
179
  while (queue.size > 0) {
@@ -237,7 +236,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
237
236
  * the value of the nodes will be `undefined`.
238
237
  * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
239
238
  */
240
- addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], values?: V[]): (N | null | undefined)[] {
239
+ addMany(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: V[]): (N | null | undefined)[] {
241
240
  // TODO not sure addMany not be run multi times
242
241
  return keysOrNodes.map((keyOrNode, i) => {
243
242
  if (keyOrNode instanceof BinaryTreeNode) {
@@ -262,14 +261,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
262
261
  * array. Each value in the `data` array will be assigned to the
263
262
  * @returns The method is returning a boolean value.
264
263
  */
265
- refill(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: Array<V>): boolean {
264
+ refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], data?: Array<V>): boolean {
266
265
  this.clear();
267
266
  return keysOrNodes.length === this.addMany(keysOrNodes, data).length;
268
267
  }
269
268
 
270
269
  delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult<N>[];
271
270
 
272
- delete<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C): BinaryTreeDeletedResult<N>[];
271
+ delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BinaryTreeDeletedResult<N>[];
273
272
 
274
273
  delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeletedResult<N>[];
275
274
 
@@ -288,7 +287,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
288
287
  * `this.defaultOneParamCallback`, which
289
288
  */
290
289
  delete<C extends BTNCallback<N>>(
291
- identifier: ReturnType<C> | null,
290
+ identifier: ReturnType<C> | null | undefined,
292
291
  callback: C = this.defaultOneParamCallback as C
293
292
  ): BinaryTreeDeletedResult<N>[] {
294
293
  const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
@@ -298,8 +297,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
298
297
  const curr = this.getNode(identifier, callback);
299
298
  if (!curr) return bstDeletedResult;
300
299
 
301
- const parent: N | null = curr?.parent ? curr.parent : null;
302
- let needBalanced: N | null = null,
300
+ const parent: N | null | undefined = curr?.parent ? curr.parent : null;
301
+ let needBalanced: N | null | undefined = null,
303
302
  orgCurrent = curr;
304
303
 
305
304
  if (!curr.left) {
@@ -337,16 +336,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
337
336
  /**
338
337
  * The function `getDepth` calculates the depth of a given node in a binary tree relative to a
339
338
  * specified root node.
340
- * @param {BTNKey | N | null} distNode - The `distNode` parameter represents the node
339
+ * @param {BTNKey | N | null | undefined} distNode - The `distNode` parameter represents the node
341
340
  * whose depth we want to find in the binary tree. It can be either a node object (`N`), a key value
342
341
  * of the node (`BTNKey`), or `null`.
343
- * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the
342
+ * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
344
343
  * starting node from which we want to calculate the depth. It can be either a node object or the key
345
344
  * of a node in the binary tree. If no value is provided for `beginRoot`, it defaults to the root
346
345
  * node of the binary tree.
347
346
  * @returns the depth of the `distNode` relative to the `beginRoot`.
348
347
  */
349
- getDepth(distNode: BTNKey | N | null, beginRoot: BTNKey | N | null = this.root): number {
348
+ getDepth(distNode: BTNKey | N | null | undefined, beginRoot: BTNKey | N | null | undefined = this.root): number {
350
349
  if (typeof distNode === 'number') distNode = this.getNode(distNode);
351
350
  if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
352
351
  let depth = 0;
@@ -363,7 +362,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
363
362
  /**
364
363
  * The `getHeight` function calculates the maximum height of a binary tree using either recursive or
365
364
  * iterative approach.
366
- * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the
365
+ * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
367
366
  * starting node from which the height of the binary tree is calculated. It can be either a node
368
367
  * object (`N`), a key value of a node in the tree (`BTNKey`), or `null` if no starting
369
368
  * node is specified. If `
@@ -372,7 +371,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
372
371
  * possible values:
373
372
  * @returns the height of the binary tree.
374
373
  */
375
- getHeight(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): number {
374
+ getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
376
375
  if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
377
376
  if (!beginRoot) return -1;
378
377
 
@@ -390,7 +389,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
390
389
  return -1;
391
390
  }
392
391
 
393
- const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}];
392
+ const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}];
394
393
  let maxHeight = 0;
395
394
 
396
395
  while (stack.length > 0) {
@@ -414,14 +413,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
414
413
  /**
415
414
  * The `getMinHeight` function calculates the minimum height of a binary tree using either a
416
415
  * recursive or iterative approach.
417
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to
416
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which we want to
418
417
  * calculate the minimum height of the tree. It is optional and defaults to the root of the tree if
419
418
  * not provided.
420
419
  * @param iterationType - The `iterationType` parameter is used to determine the method of iteration
421
420
  * to calculate the minimum height of a binary tree. It can have two possible values:
422
421
  * @returns The function `getMinHeight` returns the minimum height of a binary tree.
423
422
  */
424
- getMinHeight(beginRoot: N | null = this.root, iterationType = this.iterationType): number {
423
+ getMinHeight(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): number {
425
424
  if (!beginRoot) return -1;
426
425
 
427
426
  if (iterationType === IterationType.RECURSIVE) {
@@ -437,7 +436,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
437
436
  } else {
438
437
  const stack: N[] = [];
439
438
  let node: N | null | undefined = beginRoot,
440
- last: N | null = null;
439
+ last: N | null | undefined = null;
441
440
  const depths: Map<N, number> = new Map();
442
441
 
443
442
  while (stack.length > 0 || node) {
@@ -466,11 +465,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
466
465
  /**
467
466
  * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the
468
467
  * height of the tree.
469
- * @param {N | null} beginRoot - The parameter `beginRoot` is of type `N | null`, which means it can
468
+ * @param {N | null | undefined} beginRoot - The parameter `beginRoot` is of type `N | null | undefined`, which means it can
470
469
  * either be of type `N` (representing a node in a tree) or `null` (representing an empty tree).
471
470
  * @returns The method is returning a boolean value.
472
471
  */
473
- isPerfectlyBalanced(beginRoot: N | null = this.root): boolean {
472
+ isPerfectlyBalanced(beginRoot: N | null | undefined = this.root): boolean {
474
473
  return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
475
474
  }
476
475
 
@@ -478,15 +477,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
478
477
  identifier: BTNKey,
479
478
  callback?: C,
480
479
  onlyOne?: boolean,
481
- beginRoot?: N | null,
480
+ beginRoot?: N | null | undefined,
482
481
  iterationType?: IterationType
483
482
  ): N[];
484
483
 
485
484
  getNodes<C extends BTNCallback<N, N>>(
486
- identifier: N | null,
485
+ identifier: N | null | undefined,
487
486
  callback?: C,
488
487
  onlyOne?: boolean,
489
- beginRoot?: N | null,
488
+ beginRoot?: N | null | undefined,
490
489
  iterationType?: IterationType
491
490
  ): N[];
492
491
 
@@ -494,7 +493,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
494
493
  identifier: ReturnType<C>,
495
494
  callback: C,
496
495
  onlyOne?: boolean,
497
- beginRoot?: N | null,
496
+ beginRoot?: N | null | undefined,
498
497
  iterationType?: IterationType
499
498
  ): N[];
500
499
 
@@ -512,7 +511,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
512
511
  * first node that matches the identifier. If set to true, the function will return an array with
513
512
  * only one element (or an empty array if no matching node is found). If set to false (default), the
514
513
  * function will continue searching for all
515
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which the
514
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which the
516
515
  * traversal of the binary tree will begin. It is optional and defaults to the root of the binary
517
516
  * tree.
518
517
  * @param iterationType - The `iterationType` parameter determines the type of iteration used to
@@ -520,10 +519,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
520
519
  * @returns The function `getNodes` returns an array of nodes (`N[]`).
521
520
  */
522
521
  getNodes<C extends BTNCallback<N>>(
523
- identifier: ReturnType<C> | null,
522
+ identifier: ReturnType<C> | null | undefined,
524
523
  callback: C = this.defaultOneParamCallback as C,
525
524
  onlyOne = false,
526
- beginRoot: N | null = this.root,
525
+ beginRoot: N | null | undefined = this.root,
527
526
  iterationType = this.iterationType
528
527
  ): N[] {
529
528
  if (!beginRoot) return [];
@@ -563,21 +562,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
563
562
  has<C extends BTNCallback<N, BTNKey>>(
564
563
  identifier: BTNKey,
565
564
  callback?: C,
566
- beginRoot?: N | null,
565
+ beginRoot?: N | null | undefined,
567
566
  iterationType?: IterationType
568
567
  ): boolean;
569
568
 
570
569
  has<C extends BTNCallback<N, N>>(
571
- identifier: N | null,
570
+ identifier: N | null | undefined,
572
571
  callback?: C,
573
- beginRoot?: N | null,
572
+ beginRoot?: N | null | undefined,
574
573
  iterationType?: IterationType
575
574
  ): boolean;
576
575
 
577
576
  has<C extends BTNCallback<N>>(
578
- identifier: ReturnType<C> | null,
577
+ identifier: ReturnType<C> | null | undefined,
579
578
  callback: C,
580
- beginRoot?: N | null,
579
+ beginRoot?: N | null | undefined,
581
580
  iterationType?: IterationType
582
581
  ): boolean;
583
582
 
@@ -599,7 +598,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
599
598
  * @returns a boolean value.
600
599
  */
601
600
  has<C extends BTNCallback<N>>(
602
- identifier: ReturnType<C> | null,
601
+ identifier: ReturnType<C> | null | undefined,
603
602
  callback: C = this.defaultOneParamCallback as C,
604
603
  beginRoot = this.root,
605
604
  iterationType = this.iterationType
@@ -612,23 +611,23 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
612
611
  getNode<C extends BTNCallback<N, BTNKey>>(
613
612
  identifier: BTNKey,
614
613
  callback?: C,
615
- beginRoot?: N | null,
614
+ beginRoot?: N | null | undefined,
616
615
  iterationType?: IterationType
617
- ): N | null;
616
+ ): N | null | undefined;
618
617
 
619
618
  getNode<C extends BTNCallback<N, N>>(
620
- identifier: N | null,
619
+ identifier: N | null | undefined,
621
620
  callback?: C,
622
- beginRoot?: N | null,
621
+ beginRoot?: N | null | undefined,
623
622
  iterationType?: IterationType
624
- ): N | null;
623
+ ): N | null | undefined;
625
624
 
626
625
  getNode<C extends BTNCallback<N>>(
627
626
  identifier: ReturnType<C>,
628
627
  callback: C,
629
- beginRoot?: N | null,
628
+ beginRoot?: N | null | undefined,
630
629
  iterationType?: IterationType
631
- ): N | null;
630
+ ): N | null | undefined;
632
631
 
633
632
  /**
634
633
  * The function `get` returns the first node in a binary tree that matches the given property or key.
@@ -646,11 +645,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
646
645
  * @returns either the found node (of type N) or null if no node is found.
647
646
  */
648
647
  getNode<C extends BTNCallback<N>>(
649
- identifier: ReturnType<C> | null,
648
+ identifier: ReturnType<C> | null | undefined,
650
649
  callback: C = this.defaultOneParamCallback as C,
651
650
  beginRoot = this.root,
652
651
  iterationType = this.iterationType
653
- ): N | null {
652
+ ): N | null | undefined {
654
653
  if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
655
654
 
656
655
  return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
@@ -659,21 +658,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
659
658
  get<C extends BTNCallback<N, BTNKey>>(
660
659
  identifier: BTNKey,
661
660
  callback?: C,
662
- beginRoot?: N | null,
661
+ beginRoot?: N | null | undefined,
663
662
  iterationType?: IterationType
664
663
  ): V | undefined;
665
664
 
666
665
  get<C extends BTNCallback<N, N>>(
667
- identifier: N | null,
666
+ identifier: N | null | undefined,
668
667
  callback?: C,
669
- beginRoot?: N | null,
668
+ beginRoot?: N | null | undefined,
670
669
  iterationType?: IterationType
671
670
  ): V | undefined;
672
671
 
673
672
  get<C extends BTNCallback<N>>(
674
673
  identifier: ReturnType<C>,
675
674
  callback: C,
676
- beginRoot?: N | null,
675
+ beginRoot?: N | null | undefined,
677
676
  iterationType?: IterationType
678
677
  ): V | undefined;
679
678
 
@@ -693,7 +692,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
693
692
  * @returns either the found value (of type V) or undefined if no node value is found.
694
693
  */
695
694
  get<C extends BTNCallback<N>>(
696
- identifier: ReturnType<C> | null,
695
+ identifier: ReturnType<C> | null | undefined,
697
696
  callback: C = this.defaultOneParamCallback as C,
698
697
  beginRoot = this.root,
699
698
  iterationType = this.iterationType
@@ -729,7 +728,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
729
728
  /**
730
729
  * The function `getLeftMost` returns the leftmost node in a binary tree, either using recursive or
731
730
  * iterative traversal.
732
- * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point
731
+ * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
733
732
  * for finding the leftmost node in a binary tree. It can be either a node object (`N`), a key value
734
733
  * of a node (`BTNKey`), or `null` if the tree is empty.
735
734
  * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to
@@ -737,7 +736,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
737
736
  * @returns The function `getLeftMost` returns the leftmost node (`N`) in a binary tree. If there is
738
737
  * no leftmost node, it returns `null`.
739
738
  */
740
- getLeftMost(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): N | null {
739
+ getLeftMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
741
740
  if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
742
741
 
743
742
  if (!beginRoot) return beginRoot;
@@ -763,15 +762,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
763
762
  /**
764
763
  * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or
765
764
  * iteratively.
766
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to
767
- * find the rightmost node. It is of type `N | null`, which means it can either be a node of type `N`
765
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which we want to
766
+ * find the rightmost node. It is of type `N | null | undefined`, which means it can either be a node of type `N`
768
767
  * or `null`. If it is `null`, it means there is no starting node
769
768
  * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to
770
769
  * be performed when finding the rightmost node in a binary tree. It can have two possible values:
771
770
  * @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If the
772
771
  * `beginRoot` parameter is `null`, it returns `null`.
773
772
  */
774
- getRightMost(beginRoot: N | null = this.root, iterationType = this.iterationType): N | null {
773
+ getRightMost(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
775
774
  // TODO support get right most by passing key in
776
775
  if (!beginRoot) return beginRoot;
777
776
 
@@ -802,7 +801,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
802
801
  * possible values:
803
802
  * @returns The function `isSubtreeBST` returns a boolean value.
804
803
  */
805
- isSubtreeBST(beginRoot: N | null, iterationType = this.iterationType): boolean {
804
+ isSubtreeBST(beginRoot: N | null | undefined, iterationType = this.iterationType): boolean {
806
805
  // TODO there is a bug
807
806
  if (!beginRoot) return true;
808
807
 
@@ -847,24 +846,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
847
846
 
848
847
  subTreeTraverse<C extends BTNCallback<N>>(
849
848
  callback?: C,
850
- beginRoot?: BTNKey | N | null,
849
+ beginRoot?: BTNKey | N | null | undefined,
851
850
  iterationType?: IterationType,
852
851
  includeNull?: false
853
- ): ReturnType<C>[]
852
+ ): ReturnType<C>[];
854
853
 
855
854
  subTreeTraverse<C extends BTNCallback<N>>(
856
855
  callback?: C,
857
- beginRoot?: BTNKey | N | null,
856
+ beginRoot?: BTNKey | N | null | undefined,
858
857
  iterationType?: IterationType,
859
858
  includeNull?: undefined
860
- ): ReturnType<C>[]
859
+ ): ReturnType<C>[];
861
860
 
862
- subTreeTraverse<C extends BTNCallback<N | null>>(
861
+ subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
863
862
  callback?: C,
864
- beginRoot?: BTNKey | N | null,
863
+ beginRoot?: BTNKey | N | null | undefined,
865
864
  iterationType?: IterationType,
866
865
  includeNull?: true
867
- ): ReturnType<C>[]
866
+ ): ReturnType<C>[];
868
867
 
869
868
  /**
870
869
  * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
@@ -873,7 +872,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
873
872
  * subtree traversal. It takes a single argument, which is the current node being traversed, and
874
873
  * returns a value. The return values from each callback invocation will be collected and returned as
875
874
  * an array.
876
- * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point
875
+ * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
877
876
  * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to
878
877
  * start from the root of the tree.
879
878
  * @param iterationType - The `iterationType` parameter determines the type of traversal to be
@@ -881,75 +880,87 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
881
880
  * @param includeNull - The choice to output null values during binary tree traversal should be provided.
882
881
  * @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
883
882
  */
884
- subTreeTraverse<C extends BTNCallback<N | null>>(
883
+ subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
885
884
  callback: C = this.defaultOneParamCallback as C,
886
- beginRoot: BTNKey | N | null = this.root,
885
+ beginRoot: BTNKey | N | null | undefined = this.root,
887
886
  iterationType = this.iterationType,
888
887
  includeNull = false
889
888
  ): ReturnType<C>[] {
890
889
  if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
891
890
 
892
- const ans: (ReturnType<BTNCallback<N>> | null)[] = [];
891
+ const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
893
892
  if (!beginRoot) return ans;
894
893
 
895
894
  if (iterationType === IterationType.RECURSIVE) {
896
- const _traverse = (cur: N | null) => {
895
+ const _traverse = (cur: N | null | undefined) => {
897
896
  if (cur !== undefined) {
898
897
  ans.push(callback(cur));
899
898
  if (includeNull) {
900
- cur !== null && cur.left !== undefined && _traverse(cur.left);
901
- cur !== null && cur.right !== undefined && _traverse(cur.right);
899
+ cur && this.isNodeOrNull(cur.left) && _traverse(cur.left);
900
+ cur && this.isNodeOrNull(cur.right) && _traverse(cur.right);
902
901
  } else {
903
- cur !== null && cur.left && _traverse(cur.left);
904
- cur !== null && cur.right && _traverse(cur.right);
902
+ cur && cur.left && _traverse(cur.left);
903
+ cur && cur.right && _traverse(cur.right);
905
904
  }
906
905
  }
907
906
  };
908
907
 
909
908
  _traverse(beginRoot);
910
909
  } else {
911
- const stack: (N| null)[] = [beginRoot];
910
+ const stack: (N | null | undefined)[] = [beginRoot];
912
911
 
913
912
  while (stack.length > 0) {
914
913
  const cur = stack.pop();
915
914
  if (cur !== undefined) {
916
915
  ans.push(callback(cur));
917
916
  if (includeNull) {
918
- cur !== null && cur.right !== undefined && stack.push(cur.right);
919
- cur !== null && cur.left !== undefined && stack.push(cur.left);
917
+ cur && this.isNodeOrNull(cur.right) && stack.push(cur.right);
918
+ cur && this.isNodeOrNull(cur.left) && stack.push(cur.left);
920
919
  } else {
921
- cur !== null && cur.right && stack.push(cur.right);
922
- cur !== null && cur.left && stack.push(cur.left);
920
+ cur && cur.right && stack.push(cur.right);
921
+ cur && cur.left && stack.push(cur.left);
923
922
  }
924
923
  }
925
924
  }
926
925
  }
927
926
  return ans;
928
927
  }
928
+
929
+ isNode(node: any): node is N {
930
+ return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
931
+ }
932
+
933
+ isNIL(node: any) {
934
+ return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
935
+ }
936
+
937
+ isNodeOrNull(node: any): node is (N | null){
938
+ return this.isNode(node) || node === null;
939
+ }
929
940
 
930
941
  dfs<C extends BTNCallback<N>>(
931
942
  callback?: C,
932
943
  pattern?: DFSOrderPattern,
933
- beginRoot?: N | null,
944
+ beginRoot?: N | null | undefined,
934
945
  iterationType?: IterationType,
935
946
  includeNull?: false
936
- ): ReturnType<C>[]
947
+ ): ReturnType<C>[];
937
948
 
938
949
  dfs<C extends BTNCallback<N>>(
939
950
  callback?: C,
940
951
  pattern?: DFSOrderPattern,
941
- beginRoot?: N | null,
952
+ beginRoot?: N | null | undefined,
942
953
  iterationType?: IterationType,
943
954
  includeNull?: undefined
944
- ): ReturnType<C>[]
955
+ ): ReturnType<C>[];
945
956
 
946
- dfs<C extends BTNCallback<N | null>>(
957
+ dfs<C extends BTNCallback<N | null | undefined>>(
947
958
  callback?: C,
948
959
  pattern?: DFSOrderPattern,
949
- beginRoot?: N | null,
960
+ beginRoot?: N | null | undefined,
950
961
  iterationType?: IterationType,
951
962
  includeNull?: true
952
- ): ReturnType<C>[]
963
+ ): ReturnType<C>[];
953
964
 
954
965
  /**
955
966
  * The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback
@@ -959,7 +970,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
959
970
  * is `this.defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
960
971
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
961
972
  * nodes are visited during the depth-first search. There are three possible values for `pattern`:
962
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
973
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
963
974
  * search. It determines where the search will begin in the tree or graph structure. If `beginRoot`
964
975
  * is `null`, an empty array will be returned.
965
976
  * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
@@ -967,49 +978,49 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
967
978
  * @param includeNull - The choice to output null values during binary tree traversal should be provided.
968
979
  * @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
969
980
  */
970
- dfs<C extends BTNCallback<N | null>>(
981
+ dfs<C extends BTNCallback<N | null | undefined>>(
971
982
  callback: C = this.defaultOneParamCallback as C,
972
983
  pattern: DFSOrderPattern = 'in',
973
- beginRoot: N | null = this.root,
984
+ beginRoot: N | null | undefined = this.root,
974
985
  iterationType: IterationType = IterationType.ITERATIVE,
975
986
  includeNull = false
976
987
  ): ReturnType<C>[] {
977
988
  if (!beginRoot) return [];
978
989
  const ans: ReturnType<C>[] = [];
979
990
  if (iterationType === IterationType.RECURSIVE) {
980
- const _traverse = (node: N | null) => {
991
+ const _traverse = (node: N | null | undefined) => {
981
992
  switch (pattern) {
982
993
  case 'in':
983
994
  if (includeNull) {
984
- if (node !== null && node.left !== undefined) _traverse(node.left);
985
- ans.push(callback(node));
986
- if (node !== null && node.right !== undefined) _traverse(node.right);
995
+ if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
996
+ this.isNodeOrNull(node) && ans.push(callback(node));
997
+ if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
987
998
  } else {
988
- if (node !== null && node.left) _traverse(node.left);
989
- ans.push(callback(node));
990
- if (node !== null && node.right) _traverse(node.right);
999
+ if (node && node.left) _traverse(node.left);
1000
+ this.isNode(node) && ans.push(callback(node));
1001
+ if (node && node.right) _traverse(node.right);
991
1002
  }
992
1003
  break;
993
1004
  case 'pre':
994
1005
  if (includeNull) {
995
- ans.push(callback(node));
996
- if (node !== null && node.left !== undefined) _traverse(node.left);
997
- if (node !== null && node.right !== undefined) _traverse(node.right);
1006
+ this.isNodeOrNull(node) && ans.push(callback(node));
1007
+ if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
1008
+ if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
998
1009
  } else {
999
- ans.push(callback(node));
1000
- if (node !== null && node.left) _traverse(node.left);
1001
- if (node !== null && node.right) _traverse(node.right);
1010
+ this.isNode(node) && ans.push(callback(node));
1011
+ if (node && node.left) _traverse(node.left);
1012
+ if (node && node.right) _traverse(node.right);
1002
1013
  }
1003
1014
  break;
1004
1015
  case 'post':
1005
1016
  if (includeNull) {
1006
- if (node !== null && node.left !== undefined) _traverse(node.left);
1007
- if (node !== null && node.right !== undefined) _traverse(node.right);
1008
- ans.push(callback(node));
1017
+ if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
1018
+ if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
1019
+ this.isNodeOrNull(node) && ans.push(callback(node));
1009
1020
  } else {
1010
- if (node !== null && node.left) _traverse(node.left);
1011
- if (node !== null && node.right) _traverse(node.right);
1012
- ans.push(callback(node));
1021
+ if (node && node.left) _traverse(node.left);
1022
+ if (node && node.right) _traverse(node.right);
1023
+ this.isNode(node) && ans.push(callback(node));
1013
1024
  }
1014
1025
 
1015
1026
  break;
@@ -1019,11 +1030,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1019
1030
  _traverse(beginRoot);
1020
1031
  } else {
1021
1032
  // 0: visit, 1: print
1022
- const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}];
1033
+ const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}];
1023
1034
 
1024
1035
  while (stack.length > 0) {
1025
1036
  const cur = stack.pop();
1026
- if (cur === undefined) continue;
1037
+ if (cur === undefined || this.isNIL(cur.node)) continue;
1027
1038
  if (includeNull) {
1028
1039
  if (cur.node === undefined) continue;
1029
1040
  } else {
@@ -1063,24 +1074,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1063
1074
 
1064
1075
  bfs<C extends BTNCallback<N>>(
1065
1076
  callback?: C,
1066
- beginRoot?: N | null,
1077
+ beginRoot?: N | null | undefined,
1067
1078
  iterationType?: IterationType,
1068
1079
  includeNull?: false
1069
- ): ReturnType<C>[]
1080
+ ): ReturnType<C>[];
1070
1081
 
1071
1082
  bfs<C extends BTNCallback<N>>(
1072
1083
  callback?: C,
1073
- beginRoot?: N | null,
1084
+ beginRoot?: N | null | undefined,
1074
1085
  iterationType?: IterationType,
1075
1086
  includeNull?: undefined
1076
- ): ReturnType<C>[]
1087
+ ): ReturnType<C>[];
1077
1088
 
1078
- bfs<C extends BTNCallback<N | null>>(
1089
+ bfs<C extends BTNCallback<N | null | undefined>>(
1079
1090
  callback?: C,
1080
- beginRoot?: N | null,
1091
+ beginRoot?: N | null | undefined,
1081
1092
  iterationType?: IterationType,
1082
1093
  includeNull?: true
1083
- ): ReturnType<C>[]
1094
+ ): ReturnType<C>[];
1084
1095
 
1085
1096
  /**
1086
1097
  * The bfs function performs a breadth-first search traversal on a binary tree, executing a callback
@@ -1088,7 +1099,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1088
1099
  * @param callback - The `callback` parameter is a function that will be called for each node in the
1089
1100
  * breadth-first search. It takes a node of type `N` as its argument and returns a value of type
1090
1101
  * `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this.defaultOneParamCallback
1091
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
1102
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
1092
1103
  * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
1093
1104
  * will not be performed and an empty array will be returned.
1094
1105
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be used
@@ -1096,9 +1107,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1096
1107
  * @param includeNull - The choice to output null values during binary tree traversal should be provided.
1097
1108
  * @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
1098
1109
  */
1099
- bfs<C extends BTNCallback<N | null>>(
1110
+ bfs<C extends BTNCallback<N | null | undefined>>(
1100
1111
  callback: C = this.defaultOneParamCallback as C,
1101
- beginRoot: N | null = this.root,
1112
+ beginRoot: N | null | undefined = this.root,
1102
1113
  iterationType = this.iterationType,
1103
1114
  includeNull = false
1104
1115
  ): ReturnType<C>[] {
@@ -1107,7 +1118,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1107
1118
  const ans: ReturnType<BTNCallback<N>>[] = [];
1108
1119
 
1109
1120
  if (iterationType === IterationType.RECURSIVE) {
1110
- const queue: Queue<N | null> = new Queue<N | null>([beginRoot]);
1121
+ const queue: Queue<N | null | undefined> = new Queue<N | null | undefined>([beginRoot]);
1111
1122
 
1112
1123
  const traverse = (level: number) => {
1113
1124
  if (queue.size === 0) return;
@@ -1116,20 +1127,19 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1116
1127
  ans.push(callback(current));
1117
1128
 
1118
1129
  if (includeNull) {
1119
- if (current && current.left !== undefined) queue.push(current.left);
1120
- if (current && current.right !== undefined) queue.push(current.right);
1130
+ if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
1131
+ if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
1121
1132
  } else {
1122
1133
  if (current.left) queue.push(current.left);
1123
1134
  if (current.right) queue.push(current.right);
1124
1135
  }
1125
1136
 
1126
-
1127
1137
  traverse(level + 1);
1128
1138
  };
1129
1139
 
1130
1140
  traverse(0);
1131
1141
  } else {
1132
- const queue = new Queue<N | null>([beginRoot]);
1142
+ const queue = new Queue<N | null | undefined>([beginRoot]);
1133
1143
  while (queue.size > 0) {
1134
1144
  const levelSize = queue.size;
1135
1145
 
@@ -1138,13 +1148,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1138
1148
  ans.push(callback(current));
1139
1149
 
1140
1150
  if (includeNull) {
1141
- if (current !== null && current.left !== undefined) queue.push(current.left);
1142
- if (current !== null && current.right !== undefined) queue.push(current.right);
1151
+ if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
1152
+ if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
1143
1153
  } else {
1144
1154
  if (current.left) queue.push(current.left);
1145
1155
  if (current.right) queue.push(current.right);
1146
1156
  }
1147
-
1148
1157
  }
1149
1158
  }
1150
1159
  }
@@ -1152,25 +1161,25 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1152
1161
  }
1153
1162
 
1154
1163
  listLevels<C extends BTNCallback<N>>(
1155
- callback?: C ,
1156
- beginRoot?: N | null ,
1164
+ callback?: C,
1165
+ beginRoot?: N | null | undefined,
1157
1166
  iterationType?: IterationType,
1158
1167
  includeNull?: false
1159
- ): ReturnType<C>[][]
1168
+ ): ReturnType<C>[][];
1160
1169
 
1161
1170
  listLevels<C extends BTNCallback<N>>(
1162
- callback?: C ,
1163
- beginRoot?: N | null ,
1171
+ callback?: C,
1172
+ beginRoot?: N | null | undefined,
1164
1173
  iterationType?: IterationType,
1165
1174
  includeNull?: undefined
1166
- ): ReturnType<C>[][]
1175
+ ): ReturnType<C>[][];
1167
1176
 
1168
- listLevels<C extends BTNCallback<N | null>>(
1169
- callback?: C ,
1170
- beginRoot?: N | null ,
1177
+ listLevels<C extends BTNCallback<N | null | undefined>>(
1178
+ callback?: C,
1179
+ beginRoot?: N | null | undefined,
1171
1180
  iterationType?: IterationType,
1172
1181
  includeNull?: true
1173
- ): ReturnType<C>[][]
1182
+ ): ReturnType<C>[][];
1174
1183
 
1175
1184
  /**
1176
1185
  * The `listLevels` function takes a binary tree node and a callback function, and returns an array
@@ -1178,7 +1187,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1178
1187
  * @param {C} callback - The `callback` parameter is a function that will be called on each node in
1179
1188
  * the tree. It takes a node as input and returns a value. The return type of the callback function
1180
1189
  * is determined by the generic type `C`.
1181
- * @param {N | null} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree
1190
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree
1182
1191
  * traversal. It can be any node in the binary tree. If no node is provided, the traversal will start
1183
1192
  * from the root node of the binary tree.
1184
1193
  * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done
@@ -1188,9 +1197,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1188
1197
  * level in a binary tree. Each inner array contains the return type of the provided callback
1189
1198
  * function `C` applied to the nodes at that level.
1190
1199
  */
1191
- listLevels<C extends BTNCallback<N | null>>(
1200
+ listLevels<C extends BTNCallback<N | null | undefined>>(
1192
1201
  callback: C = this.defaultOneParamCallback as C,
1193
- beginRoot: N | null = this.root,
1202
+ beginRoot: N | null | undefined = this.root,
1194
1203
  iterationType = this.iterationType,
1195
1204
  includeNull = false
1196
1205
  ): ReturnType<C>[][] {
@@ -1198,13 +1207,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1198
1207
  const levelsNodes: ReturnType<C>[][] = [];
1199
1208
 
1200
1209
  if (iterationType === IterationType.RECURSIVE) {
1201
- const _recursive = (node: N | null, level: number) => {
1210
+ const _recursive = (node: N | null | undefined, level: number) => {
1202
1211
  if (!levelsNodes[level]) levelsNodes[level] = [];
1203
1212
  levelsNodes[level].push(callback(node));
1204
1213
  if (includeNull) {
1205
- if (node && node.left !== undefined) _recursive(node.left, level + 1);
1206
- if (node && node.right !== undefined) _recursive(node.right, level + 1);
1207
- } else {
1214
+ if (node && this.isNodeOrNull(node.left)) _recursive(node.left, level + 1);
1215
+ if (node && this.isNodeOrNull(node.right)) _recursive(node.right, level + 1);
1216
+ } else {
1208
1217
  if (node && node.left) _recursive(node.left, level + 1);
1209
1218
  if (node && node.right) _recursive(node.right, level + 1);
1210
1219
  }
@@ -1212,7 +1221,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1212
1221
 
1213
1222
  _recursive(beginRoot, 0);
1214
1223
  } else {
1215
- const stack: [N | null, number][] = [[beginRoot, 0]];
1224
+ const stack: [N | null | undefined, number][] = [[beginRoot, 0]];
1216
1225
 
1217
1226
  while (stack.length > 0) {
1218
1227
  const head = stack.pop()!;
@@ -1222,9 +1231,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1222
1231
  levelsNodes[level].push(callback(node));
1223
1232
 
1224
1233
  if (includeNull) {
1225
- if (node && node.right !== undefined) stack.push([node.right, level + 1]);
1226
- if (node && node.left !== undefined) stack.push([node.left, level + 1]);
1227
- } else {
1234
+ if (node && this.isNodeOrNull(node.right)) stack.push([node.right, level + 1]);
1235
+ if (node && this.isNodeOrNull(node.left)) stack.push([node.left, level + 1]);
1236
+ } else {
1228
1237
  if (node && node.right) stack.push([node.right, level + 1]);
1229
1238
  if (node && node.left) stack.push([node.left, level + 1]);
1230
1239
  }
@@ -1273,8 +1282,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1273
1282
  return y;
1274
1283
  }
1275
1284
 
1276
- // --- start additional methods ---
1277
-
1278
1285
  /**
1279
1286
  * The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal
1280
1287
  * algorithm and returns an array of values obtained by applying a callback function to each node.
@@ -1284,7 +1291,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1284
1291
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
1285
1292
  * determines the order in which the nodes of a binary tree are traversed. It can have one of the
1286
1293
  * following values:
1287
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris
1294
+ * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the Morris
1288
1295
  * traversal. It specifies the root node of the tree from which the traversal should begin. If
1289
1296
  * `beginRoot` is `null`, an empty array will be returned.
1290
1297
  * @returns The `morris` function returns an array of `ReturnType<BTNCallback<N>>` values.
@@ -1292,7 +1299,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1292
1299
  morris<C extends BTNCallback<N>>(
1293
1300
  callback: C = this.defaultOneParamCallback as C,
1294
1301
  pattern: DFSOrderPattern = 'in',
1295
- beginRoot: N | null = this.root
1302
+ beginRoot: N | null | undefined = this.root
1296
1303
  ): ReturnType<C>[] {
1297
1304
  if (beginRoot === null) return [];
1298
1305
  const ans: ReturnType<BTNCallback<N>>[] = [];
@@ -1309,7 +1316,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1309
1316
  }
1310
1317
  return pre;
1311
1318
  };
1312
- const _printEdge = (node: N | null) => {
1319
+ const _printEdge = (node: N | null | undefined) => {
1313
1320
  const tail: N | null | undefined = _reverseEdge(node);
1314
1321
  let cur: N | null | undefined = tail;
1315
1322
  while (cur) {
@@ -1374,6 +1381,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1374
1381
  return ans;
1375
1382
  }
1376
1383
 
1384
+ // --- start additional methods ---
1385
+
1377
1386
  /**
1378
1387
  * The above function is an iterator for a binary tree that can be used to traverse the tree in
1379
1388
  * either an iterative or recursive manner.
@@ -1383,7 +1392,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1383
1392
  * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
1384
1393
  * binary tree nodes in a specific order.
1385
1394
  */
1386
- * [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1395
+ *[Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1387
1396
  if (!node) {
1388
1397
  return;
1389
1398
  }
@@ -1416,6 +1425,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1416
1425
  }
1417
1426
  }
1418
1427
 
1428
+ protected defaultOneParamCallback = (node: N) => node.key;
1429
+
1419
1430
  /**
1420
1431
  * Swap the data of two nodes in the binary tree.
1421
1432
  * @param {N} srcNode - The source node to swap.
@@ -1439,7 +1450,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1439
1450
 
1440
1451
  /**
1441
1452
  * The function `_addTo` adds a new node to a binary tree if there is an available position.
1442
- * @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to
1453
+ * @param {N | null | undefined} newNode - The `newNode` parameter represents the node that you want to add to
1443
1454
  * the binary tree. It can be either a node object or `null`.
1444
1455
  * @param {N} parent - The `parent` parameter represents the parent node to which the new node will
1445
1456
  * be added as a child.
@@ -1448,7 +1459,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1448
1459
  * the binary tree. If neither the left nor right child is available, the function returns undefined.
1449
1460
  * If the parent node is null, the function also returns undefined.
1450
1461
  */
1451
- protected _addTo(newNode: N | null, parent: N): N | null | undefined {
1462
+ protected _addTo(newNode: N | null | undefined, parent: N): N | null | undefined {
1452
1463
  if (parent) {
1453
1464
  // When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
1454
1465
  // In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."
@@ -1475,15 +1486,73 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1475
1486
  /**
1476
1487
  * The function sets the root property of an object to a given value, and if the value is not null,
1477
1488
  * it also sets the parent property of the value to undefined.
1478
- * @param {N | null} v - The parameter `v` is of type `N | null`, which means it can either be of
1489
+ * @param {N | null | undefined} v - The parameter `v` is of type `N | null | undefined`, which means it can either be of
1479
1490
  * type `N` or `null`.
1480
1491
  */
1481
- protected _setRoot(v: N | null) {
1492
+ protected _setRoot(v: N | null | undefined) {
1482
1493
  if (v) {
1483
1494
  v.parent = undefined;
1484
1495
  }
1485
1496
  this._root = v;
1486
1497
  }
1487
1498
 
1499
+ print(beginRoot: N | null | undefined = this.root) {
1500
+ const display = (root: N | null | undefined): void => {
1501
+ const [lines, , ,] = _displayAux(root);
1502
+ for (const line of lines) {
1503
+ console.log(line);
1504
+ }
1505
+ };
1506
+
1507
+ const _displayAux = (node: N | null | undefined): [string[], number, number, number] => {
1508
+ if (node === undefined || node === null) {
1509
+ return [[], 0, 0, 0];
1510
+ }
1511
+
1512
+ if (node && node.right === undefined && node.left === undefined) {
1513
+ const line = `${node.key}`;
1514
+ const width = line.length;
1515
+ const height = 1;
1516
+ const middle = Math.floor(width / 2);
1517
+ return [[line], width, height, middle];
1518
+ }
1519
+
1520
+ if (node && node.right === undefined) {
1521
+ const [lines, n, p, x] = _displayAux(node.left);
1522
+ const s = `${node.key}`;
1523
+ const u = s.length;
1524
+ const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s;
1525
+ const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u);
1526
+ const shifted_lines = lines.map(line => line + ' '.repeat(u));
1527
+ return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)];
1528
+ }
1529
+
1530
+ if (node && node.left === undefined) {
1531
+ const [lines, n, p, u] = _displayAux(node.right);
1532
+ const s = `${node.key}`;
1533
+ const x = s.length;
1534
+ const first_line = s + '_'.repeat(x) + ' '.repeat(n - x);
1535
+ const second_line = ' '.repeat(u + x) + '\\' + ' '.repeat(n - x - 1);
1536
+ const shifted_lines = lines.map(line => ' '.repeat(u) + line);
1537
+ return [[first_line, second_line, ...shifted_lines], n + x, p + 2, Math.floor(u / 2)];
1538
+ }
1539
+
1540
+ const [left, n, p, x] = _displayAux(node.left);
1541
+ const [right, m, q, y] = _displayAux(node.right);
1542
+ const s = `${node.key}`;
1543
+ const u = s.length;
1544
+ const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s + '_'.repeat(y) + ' '.repeat(m - y);
1545
+ const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u + y) + '\\' + ' '.repeat(m - y - 1);
1546
+ if (p < q) {
1547
+ left.push(...new Array(q - p).fill(' '.repeat(n)));
1548
+ } else if (q < p) {
1549
+ right.push(...new Array(p - q).fill(' '.repeat(m)));
1550
+ }
1551
+ const zipped_lines = left.map((a, i) => a + ' '.repeat(u) + right[i]);
1552
+ return [[first_line, second_line, ...zipped_lines], n + m + u, Math.max(p, q) + 2, n + Math.floor(u / 2)];
1553
+ };
1554
+
1555
+ display(beginRoot);
1556
+ }
1488
1557
  // --- end additional methods ---
1489
1558
  }