directed-graph-typed 1.52.4 → 1.52.5

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.
Files changed (74) hide show
  1. package/dist/data-structures/base/iterable-element-base.d.ts +1 -37
  2. package/dist/data-structures/base/iterable-element-base.js +1 -37
  3. package/dist/data-structures/base/iterable-entry-base.d.ts +2 -54
  4. package/dist/data-structures/base/iterable-entry-base.js +1 -49
  5. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +0 -32
  6. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +9 -41
  7. package/dist/data-structures/binary-tree/avl-tree.d.ts +0 -46
  8. package/dist/data-structures/binary-tree/avl-tree.js +0 -46
  9. package/dist/data-structures/binary-tree/binary-tree.d.ts +82 -147
  10. package/dist/data-structures/binary-tree/binary-tree.js +299 -331
  11. package/dist/data-structures/binary-tree/bst.d.ts +1 -40
  12. package/dist/data-structures/binary-tree/bst.js +12 -44
  13. package/dist/data-structures/binary-tree/rb-tree.d.ts +0 -48
  14. package/dist/data-structures/binary-tree/rb-tree.js +2 -50
  15. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +0 -32
  16. package/dist/data-structures/binary-tree/tree-multi-map.js +9 -41
  17. package/dist/data-structures/graph/abstract-graph.d.ts +0 -75
  18. package/dist/data-structures/graph/abstract-graph.js +0 -75
  19. package/dist/data-structures/graph/directed-graph.d.ts +0 -98
  20. package/dist/data-structures/graph/directed-graph.js +0 -98
  21. package/dist/data-structures/graph/undirected-graph.d.ts +0 -50
  22. package/dist/data-structures/graph/undirected-graph.js +0 -50
  23. package/dist/data-structures/hash/hash-map.d.ts +5 -92
  24. package/dist/data-structures/hash/hash-map.js +27 -111
  25. package/dist/data-structures/heap/heap.d.ts +0 -32
  26. package/dist/data-structures/heap/heap.js +0 -32
  27. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +5 -88
  28. package/dist/data-structures/linked-list/doubly-linked-list.js +5 -88
  29. package/dist/data-structures/linked-list/singly-linked-list.d.ts +1 -83
  30. package/dist/data-structures/linked-list/singly-linked-list.js +2 -84
  31. package/dist/data-structures/linked-list/skip-linked-list.d.ts +1 -35
  32. package/dist/data-structures/linked-list/skip-linked-list.js +1 -35
  33. package/dist/data-structures/queue/deque.d.ts +1 -98
  34. package/dist/data-structures/queue/deque.js +3 -99
  35. package/dist/data-structures/queue/queue.d.ts +1 -54
  36. package/dist/data-structures/queue/queue.js +0 -53
  37. package/dist/data-structures/stack/stack.d.ts +1 -34
  38. package/dist/data-structures/stack/stack.js +1 -34
  39. package/dist/data-structures/tree/tree.js +2 -1
  40. package/dist/data-structures/trie/trie.d.ts +0 -64
  41. package/dist/data-structures/trie/trie.js +0 -64
  42. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +8 -0
  43. package/dist/types/data-structures/binary-tree/binary-tree.js +6 -0
  44. package/dist/types/utils/utils.d.ts +13 -12
  45. package/dist/utils/number.d.ts +13 -0
  46. package/dist/utils/number.js +13 -0
  47. package/dist/utils/utils.d.ts +125 -3
  48. package/dist/utils/utils.js +177 -21
  49. package/package.json +2 -2
  50. package/src/data-structures/base/iterable-element-base.ts +2 -42
  51. package/src/data-structures/base/iterable-entry-base.ts +3 -62
  52. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +8 -48
  53. package/src/data-structures/binary-tree/avl-tree.ts +0 -57
  54. package/src/data-structures/binary-tree/binary-tree.ts +329 -358
  55. package/src/data-structures/binary-tree/bst.ts +11 -54
  56. package/src/data-structures/binary-tree/rb-tree.ts +2 -62
  57. package/src/data-structures/binary-tree/tree-multi-map.ts +8 -48
  58. package/src/data-structures/graph/abstract-graph.ts +0 -92
  59. package/src/data-structures/graph/directed-graph.ts +0 -122
  60. package/src/data-structures/graph/undirected-graph.ts +0 -62
  61. package/src/data-structures/hash/hash-map.ts +29 -133
  62. package/src/data-structures/heap/heap.ts +0 -40
  63. package/src/data-structures/linked-list/doubly-linked-list.ts +5 -112
  64. package/src/data-structures/linked-list/singly-linked-list.ts +2 -104
  65. package/src/data-structures/linked-list/skip-linked-list.ts +1 -44
  66. package/src/data-structures/queue/deque.ts +2 -125
  67. package/src/data-structures/queue/queue.ts +1 -68
  68. package/src/data-structures/stack/stack.ts +1 -43
  69. package/src/data-structures/tree/tree.ts +1 -1
  70. package/src/data-structures/trie/trie.ts +0 -80
  71. package/src/types/data-structures/binary-tree/binary-tree.ts +8 -1
  72. package/src/types/utils/utils.ts +17 -15
  73. package/src/utils/number.ts +13 -0
  74. package/src/utils/utils.ts +174 -18
@@ -22,8 +22,9 @@ import type {
22
22
  NodeDisplayLayout,
23
23
  OptBTNOrNull
24
24
  } from '../../types';
25
+ import { DFSOperation, DFSStackItem } from '../../types';
25
26
  import { IBinaryTree } from '../../interfaces';
26
- import { trampoline } from '../../utils';
27
+ import { isComparable, trampoline } from '../../utils';
27
28
  import { Queue } from '../queue';
28
29
  import { IterableEntryBase } from '../base';
29
30
 
@@ -55,7 +56,7 @@ export class BinaryTreeNode<
55
56
  this.value = value;
56
57
  }
57
58
 
58
- protected _left?: NODE | null;
59
+ protected _left?: OptBTNOrNull<NODE>;
59
60
 
60
61
  /**
61
62
  * The function returns the value of the `_left` property, which can be of type `NODE`, `null`, or
@@ -79,7 +80,7 @@ export class BinaryTreeNode<
79
80
  this._left = v;
80
81
  }
81
82
 
82
- protected _right?: NODE | null;
83
+ protected _right?: OptBTNOrNull<NODE>;
83
84
 
84
85
  /**
85
86
  * The function returns the right node of a binary tree or null if it doesn't exist.
@@ -248,17 +249,17 @@ export class BinaryTree<
248
249
 
249
250
  if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement;
250
251
 
251
- if (this.toEntryFn) {
252
- const [key, entryValue] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R);
253
- if (key) return this.createNode(key, entryValue ?? value);
254
- else return;
255
- }
256
-
257
252
  if (this.isEntry(keyOrNodeOrEntryOrRawElement)) {
258
- const [key, value] = keyOrNodeOrEntryOrRawElement;
253
+ const [key, entryValue] = keyOrNodeOrEntryOrRawElement;
259
254
  if (key === undefined) return;
260
255
  else if (key === null) return null;
261
- else return this.createNode(key, value);
256
+ if (this.isKey(key)) return this.createNode(key, value ?? entryValue);
257
+ }
258
+
259
+ if (this.toEntryFn) {
260
+ const [key, entryValue] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R);
261
+ if (this.isKey(key)) return this.createNode(key, value ?? entryValue);
262
+ else return;
262
263
  }
263
264
 
264
265
  if (this.isKey(keyOrNodeOrEntryOrRawElement)) return this.createNode(keyOrNodeOrEntryOrRawElement, value);
@@ -266,11 +267,6 @@ export class BinaryTree<
266
267
  return;
267
268
  }
268
269
 
269
- /**
270
- * Time Complexity: O(n)
271
- * Space Complexity: O(log n)
272
- */
273
-
274
270
  /**
275
271
  * Time Complexity: O(n)
276
272
  * Space Complexity: O(log n)
@@ -287,7 +283,7 @@ export class BinaryTree<
287
283
  */
288
284
  ensureNode(
289
285
  keyOrNodeOrEntryOrRawElement: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
290
- iterationType: IterationType = 'ITERATIVE'
286
+ iterationType: IterationType = this.iterationType
291
287
  ): OptBTNOrNull<NODE> {
292
288
  if (keyOrNodeOrEntryOrRawElement === null) return null;
293
289
  if (keyOrNodeOrEntryOrRawElement === undefined) return;
@@ -296,7 +292,7 @@ export class BinaryTree<
296
292
 
297
293
  if (this.toEntryFn) {
298
294
  const [key] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R);
299
- if (key) return this.getNodeByKey(key);
295
+ if (this.isKey(key)) return this.getNodeByKey(key);
300
296
  }
301
297
 
302
298
  if (this.isEntry(keyOrNodeOrEntryOrRawElement)) {
@@ -338,7 +334,7 @@ export class BinaryTree<
338
334
  * `BTNKeyOrNodeOrEntry<K, V, NODE>`.
339
335
  * @returns a boolean value.
340
336
  */
341
- isNodeOrNull(node: R | BTNKeyOrNodeOrEntry<K, V, NODE>): node is NODE | null {
337
+ isRealNodeOrNull(node: R | BTNKeyOrNodeOrEntry<K, V, NODE>): node is NODE | null {
342
338
  return this.isRealNode(node) || node === null;
343
339
  }
344
340
 
@@ -348,10 +344,26 @@ export class BinaryTree<
348
344
  * `BTNKeyOrNodeOrEntry<K, V, NODE>`.
349
345
  * @returns a boolean value.
350
346
  */
351
- isNIL(node: R | BTNKeyOrNodeOrEntry<K, V, NODE>) {
347
+ isNIL(node: R | BTNKeyOrNodeOrEntry<K, V, NODE>): boolean {
352
348
  return node === this.NIL;
353
349
  }
354
350
 
351
+ /**
352
+ * The function `isLeaf` determines whether a given node is a leaf node in a binary tree structure.
353
+ * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} node - The `node` parameter in the `isLeaf` function
354
+ * can be either a regular node (`R`) or a `BTNKeyOrNodeOrEntry<K, V, NODE>`.
355
+ * @returns The `isLeaf` function is checking if the provided node is a leaf node in a binary tree.
356
+ * If the node is `undefined`, it returns `false`. If the node is `null`, it returns `true`.
357
+ * Otherwise, it checks if both the left and right children of the node are not real nodes, and
358
+ * returns `true` if they are not, indicating that the node is a
359
+ */
360
+ isLeaf(node: R | BTNKeyOrNodeOrEntry<K, V, NODE>): boolean {
361
+ node = this.ensureNode(node);
362
+ if (node === undefined) return false;
363
+ if (node === null) return true;
364
+ return !this.isRealNode(node.left) && !this.isRealNode(node.right);
365
+ }
366
+
355
367
  /**
356
368
  * The function checks if the input is an array with two elements, indicating it is a binary tree
357
369
  * node entry.
@@ -366,38 +378,21 @@ export class BinaryTree<
366
378
  }
367
379
 
368
380
  /**
369
- * The function checks if a given value is a valid key by evaluating its type and value.
370
- * @param {any} key - The `key` parameter can be of any type. It is the value that we want to check
371
- * if it is a valid key.
372
- * @param [isCheckValueOf=true] - The `isCheckValueOf` parameter is a boolean flag that determines
373
- * whether the function should check the valueOf() method of an object when the key is of type
374
- * 'object'. If `isCheckValueOf` is true, the function will recursively call itself with the value
375
- * returned by key.valueOf().
376
- * @returns a boolean value.
377
- */
378
- isKey(key: any, isCheckValueOf = true): key is K {
381
+ * Time Complexity O(1)
382
+ * Space Complexity O(1)
383
+ *
384
+ * The function `isKey` checks if a given key is comparable.
385
+ * @param {any} key - The `key` parameter is of type `any`, which means it can be any data type in
386
+ * TypeScript.
387
+ * @returns The function `isKey` is checking if the `key` parameter is `null` or if it is comparable.
388
+ * If the `key` is `null`, the function returns `true`. Otherwise, it returns the result of the
389
+ * `isComparable` function, which is not provided in the code snippet.
390
+ */
391
+ isKey(key: any): key is K {
379
392
  if (key === null) return true;
380
- const keyType = typeof key;
381
- if (keyType === 'string' || keyType === 'bigint' || keyType === 'boolean') return true;
382
- if (keyType === 'number') return !isNaN(key);
383
- if (keyType === 'symbol' || keyType === 'undefined') return false;
384
- if (keyType === 'function') return this.isKey(key());
385
- if (keyType === 'object') {
386
- if (typeof key.toString === 'function') return true;
387
- if (isCheckValueOf && typeof key.valueOf === 'function') {
388
- this.isKey(key.valueOf(), false);
389
- }
390
- return false;
391
- }
392
-
393
- return false;
393
+ return isComparable(key);
394
394
  }
395
395
 
396
- /**
397
- * Time Complexity O(n)
398
- * Space Complexity O(1)
399
- */
400
-
401
396
  /**
402
397
  * Time Complexity O(n)
403
398
  * Space Complexity O(1)
@@ -467,12 +462,6 @@ export class BinaryTree<
467
462
  return false; // If the insertion position cannot be found, return undefined
468
463
  }
469
464
 
470
- /**
471
- * Time Complexity: O(k * n)
472
- * Space Complexity: O(1)
473
- * Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
474
- */
475
-
476
465
  /**
477
466
  * Time Complexity: O(k * n)
478
467
  * Space Complexity: O(1)
@@ -515,12 +504,6 @@ export class BinaryTree<
515
504
  return inserted;
516
505
  }
517
506
 
518
- /**
519
- * Time Complexity: O(k * n)
520
- * Space Complexity: O(1)
521
- * "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
522
- */
523
-
524
507
  /**
525
508
  * Time Complexity: O(k * n)
526
509
  * Space Complexity: O(1)
@@ -549,11 +532,6 @@ export class BinaryTree<
549
532
 
550
533
  delete<C extends BTNCallback<NODE>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeleteResult<NODE>[];
551
534
 
552
- /**
553
- * Time Complexity: O(n)
554
- * Space Complexity: O(1)
555
- */
556
-
557
535
  /**
558
536
  * Time Complexity: O(n)
559
537
  * Space Complexity: O(1)
@@ -587,7 +565,7 @@ export class BinaryTree<
587
565
  if (!curr.left && !curr.right && !parent) {
588
566
  this._setRoot(undefined);
589
567
  } else if (curr.left) {
590
- const leftSubTreeRightMost = this.getRightMost(curr.left);
568
+ const leftSubTreeRightMost = this.getRightMost(node => node, curr.left);
591
569
  if (leftSubTreeRightMost) {
592
570
  const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
593
571
  orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
@@ -641,11 +619,6 @@ export class BinaryTree<
641
619
  iterationType?: IterationType
642
620
  ): NODE[];
643
621
 
644
- /**
645
- * Time Complexity: O(n)
646
- * Space Complexity: O(k + log n)
647
- */
648
-
649
622
  /**
650
623
  * Time Complexity: O(n)
651
624
  * Space Complexity: O(k + log n)
@@ -677,6 +650,8 @@ export class BinaryTree<
677
650
  beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
678
651
  iterationType: IterationType = this.iterationType
679
652
  ): NODE[] {
653
+ if (identifier === undefined) return [];
654
+ if (identifier === null) return [];
680
655
  beginRoot = this.ensureNode(beginRoot);
681
656
  if (!beginRoot) return [];
682
657
  callback = this._ensureCallback(identifier, callback);
@@ -734,11 +709,6 @@ export class BinaryTree<
734
709
  iterationType?: IterationType
735
710
  ): OptBTNOrNull<NODE>;
736
711
 
737
- /**
738
- * Time Complexity: O(n)
739
- * Space Complexity: O(log n).
740
- */
741
-
742
712
  /**
743
713
  * Time Complexity: O(n)
744
714
  * Space Complexity: O(log n).
@@ -766,11 +736,6 @@ export class BinaryTree<
766
736
  return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
767
737
  }
768
738
 
769
- /**
770
- * Time Complexity: O(n)
771
- * Space Complexity: O(log n)
772
- */
773
-
774
739
  /**
775
740
  * Time Complexity: O(n)
776
741
  * Space Complexity: O(log n)
@@ -783,7 +748,7 @@ export class BinaryTree<
783
748
  * It has a default value of `'ITERATIVE'`.
784
749
  * @returns a value of type NODE, null, or undefined.
785
750
  */
786
- getNodeByKey(key: K, iterationType: IterationType = 'ITERATIVE'): OptBTNOrNull<NODE> {
751
+ getNodeByKey(key: K, iterationType: IterationType = this.iterationType): OptBTNOrNull<NODE> {
787
752
  return this.getNode(key, this._DEFAULT_CALLBACK, this.root, iterationType);
788
753
  }
789
754
 
@@ -808,11 +773,6 @@ export class BinaryTree<
808
773
  iterationType?: IterationType
809
774
  ): V | undefined;
810
775
 
811
- /**
812
- * Time Complexity: O(n)
813
- * Space Complexity: O(log n)
814
- */
815
-
816
776
  /**
817
777
  * Time Complexity: O(n)
818
778
  * Space Complexity: O(log n)
@@ -864,11 +824,6 @@ export class BinaryTree<
864
824
  iterationType?: IterationType
865
825
  ): boolean;
866
826
 
867
- /**
868
- * Time Complexity: O(n)
869
- * Space Complexity: O(log n)
870
- */
871
-
872
827
  /**
873
828
  * Time Complexity: O(n)
874
829
  * Space Complexity: O(log n)
@@ -900,11 +855,6 @@ export class BinaryTree<
900
855
  return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
901
856
  }
902
857
 
903
- /**
904
- * Time Complexity: O(1)
905
- * Space Complexity: O(1)
906
- */
907
-
908
858
  /**
909
859
  * Time Complexity: O(1)
910
860
  * Space Complexity: O(1)
@@ -916,11 +866,6 @@ export class BinaryTree<
916
866
  this._size = 0;
917
867
  }
918
868
 
919
- /**
920
- * Time Complexity: O(1)
921
- * Space Complexity: O(1)
922
- */
923
-
924
869
  /**
925
870
  * Time Complexity: O(1)
926
871
  * Space Complexity: O(1)
@@ -932,11 +877,6 @@ export class BinaryTree<
932
877
  return this.size === 0;
933
878
  }
934
879
 
935
- /**
936
- * Time Complexity: O(n)
937
- * Space Complexity: O(log n)
938
- */
939
-
940
880
  /**
941
881
  * Time Complexity: O(n)
942
882
  * Space Complexity: O(log n)
@@ -953,11 +893,6 @@ export class BinaryTree<
953
893
  return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
954
894
  }
955
895
 
956
- /**
957
- * Time Complexity: O(n)
958
- * Space Complexity: O(1)
959
- */
960
-
961
896
  /**
962
897
  * Time Complexity: O(n)
963
898
  * Space Complexity: O(1)
@@ -1016,11 +951,6 @@ export class BinaryTree<
1016
951
  }
1017
952
  }
1018
953
 
1019
- /**
1020
- * Time Complexity: O(n)
1021
- * Space Complexity: O(1)
1022
- */
1023
-
1024
954
  /**
1025
955
  * Time Complexity: O(n)
1026
956
  * Space Complexity: O(1)
@@ -1052,11 +982,6 @@ export class BinaryTree<
1052
982
  return depth;
1053
983
  }
1054
984
 
1055
- /**
1056
- * Time Complexity: O(n)
1057
- * Space Complexity: O(1)
1058
- */
1059
-
1060
985
  /**
1061
986
  * Time Complexity: O(n)
1062
987
  * Space Complexity: O(1)
@@ -1103,11 +1028,6 @@ export class BinaryTree<
1103
1028
  }
1104
1029
  }
1105
1030
 
1106
- /**
1107
- * Time Complexity: O(n)
1108
- * Space Complexity: O(log n)
1109
- */
1110
-
1111
1031
  /**
1112
1032
  * Time Complexity: O(n)
1113
1033
  * Space Complexity: O(log n)
@@ -1170,11 +1090,6 @@ export class BinaryTree<
1170
1090
  }
1171
1091
  }
1172
1092
 
1173
- /**
1174
- * Time Complexity: O(log n)
1175
- * Space Complexity: O(log n)
1176
- */
1177
-
1178
1093
  /**
1179
1094
  * Time Complexity: O(log n)
1180
1095
  * Space Complexity: O(log n)
@@ -1203,32 +1118,36 @@ export class BinaryTree<
1203
1118
  return isReverse ? result.reverse() : result;
1204
1119
  }
1205
1120
 
1206
- /**
1207
- * Time Complexity: O(log n)
1208
- * Space Complexity: O(1)
1209
- */
1210
-
1211
1121
  /**
1212
1122
  * Time Complexity: O(log n)
1213
1123
  * Space Complexity: O(1)
1214
1124
  *
1215
- * The `getLeftMost` function returns the leftmost node in a binary tree, either using recursive or
1216
- * iterative traversal.
1217
- * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter represents the
1218
- * starting point for finding the leftmost node in a binary tree. It can be either a root node (`R`),
1219
- * a key or node or entry (`BTNKeyOrNodeOrEntry<K, V, NODE>`), or `null` or `undefined`.
1220
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
1221
- * of iteration to be performed. It can have two possible values:
1222
- * @returns The function `getLeftMost` returns the leftmost node in a binary tree.
1125
+ * The function `getLeftMost` retrieves the leftmost node in a binary tree using either recursive or
1126
+ * tail-recursive iteration.
1127
+ * @param {C} callback - The `callback` parameter is a function that will be called with the leftmost
1128
+ * node of a binary tree or null if the tree is empty. It has a default value of `_DEFAULT_CALLBACK`
1129
+ * if not provided explicitly.
1130
+ * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter in the
1131
+ * `getLeftMost` function represents the starting point for finding the leftmost node in a binary
1132
+ * tree. It can be either a reference to the root node of the tree (`R`), or a key, node, or entry in
1133
+ * the binary tree structure (`
1134
+ * @param {IterationType} iterationType - The `iterationType` parameter in the `getLeftMost` function
1135
+ * specifies the type of iteration to be used when traversing the binary tree nodes. It can have two
1136
+ * possible values:
1137
+ * @returns The `getLeftMost` function returns the result of the callback function `C` applied to the
1138
+ * leftmost node in the binary tree starting from the `beginRoot` node. If the `beginRoot` is `NIL`,
1139
+ * it returns the result of the callback function applied to `undefined`. If the `beginRoot` is not a
1140
+ * real node, it returns the result of the callback function applied
1223
1141
  */
1224
- getLeftMost(
1142
+ getLeftMost<C extends BTNCallback<OptBTNOrNull<NODE>>>(
1143
+ callback: C = this._DEFAULT_CALLBACK as C,
1225
1144
  beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
1226
1145
  iterationType: IterationType = this.iterationType
1227
- ): OptBTNOrNull<NODE> {
1228
- if (this.isNIL(beginRoot)) return beginRoot as NODE;
1146
+ ): ReturnType<C> {
1147
+ if (this.isNIL(beginRoot)) return callback(undefined);
1229
1148
  beginRoot = this.ensureNode(beginRoot);
1230
1149
 
1231
- if (!this.isRealNode(beginRoot)) return beginRoot;
1150
+ if (!this.isRealNode(beginRoot)) return callback(beginRoot);
1232
1151
 
1233
1152
  if (iterationType === 'RECURSIVE') {
1234
1153
  const dfs = (cur: NODE): NODE => {
@@ -1236,45 +1155,49 @@ export class BinaryTree<
1236
1155
  return dfs(cur.left);
1237
1156
  };
1238
1157
 
1239
- return dfs(beginRoot);
1158
+ return callback(dfs(beginRoot));
1240
1159
  } else {
1241
1160
  // Indirect implementation of iteration using tail recursion optimization
1242
- const dfs = trampoline((cur: NODE) => {
1161
+ const dfs = trampoline((cur: NODE): NODE => {
1243
1162
  if (!this.isRealNode(cur.left)) return cur;
1244
1163
  return dfs.cont(cur.left);
1245
1164
  });
1246
1165
 
1247
- return dfs(beginRoot);
1166
+ return callback(dfs(beginRoot));
1248
1167
  }
1249
1168
  }
1250
1169
 
1251
- /**
1252
- * Time Complexity: O(log n)
1253
- * Space Complexity: O(1)
1254
- */
1255
-
1256
1170
  /**
1257
1171
  * Time Complexity: O(log n)
1258
1172
  * Space Complexity: O(1)
1259
1173
  *
1260
- * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or
1261
- * iteratively.
1262
- * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter represents the
1263
- * starting point for finding the rightmost node in a binary tree. It can be either a root node
1264
- * (`R`), a key or node or entry (`BTNKeyOrNodeOrEntry<K, V, NODE>`), or `null` or `undefined`.
1265
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
1266
- * of iteration to be performed when finding the rightmost node in a binary tree. It can have two
1267
- * possible values:
1268
- * @returns The function `getRightMost` returns a NODE object, `null`, or `undefined`.
1269
- */
1270
- getRightMost(
1174
+ * The function `getRightMost` retrieves the rightmost node in a binary tree using either recursive
1175
+ * or iterative traversal methods.
1176
+ * @param {C} callback - The `callback` parameter is a function that will be called with the result
1177
+ * of the operation. It has a generic type `C` which extends `BTNCallback<OptBTNOrNull<NODE>>`. The
1178
+ * default value for `callback` is `this._DEFAULT_CALLBACK` if it is not provided.
1179
+ * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter in the
1180
+ * `getRightMost` function represents the starting point for finding the rightmost node in a binary
1181
+ * tree. It can be either a reference to the root node of the tree (`this.root`) or a specific key,
1182
+ * node, or entry in the tree. If
1183
+ * @param {IterationType} iterationType - The `iterationType` parameter in the `getRightMost`
1184
+ * function specifies the type of iteration to be used when finding the rightmost node in a binary
1185
+ * tree. It can have two possible values:
1186
+ * @returns The `getRightMost` function returns the result of the callback function `C` applied to
1187
+ * the rightmost node in the binary tree. The rightmost node is found either through a recursive
1188
+ * depth-first search (if `iterationType` is 'RECURSIVE') or through an indirect implementation of
1189
+ * iteration using tail recursion optimization. The result of the callback function applied to the
1190
+ * rightmost node is returned
1191
+ */
1192
+ getRightMost<C extends BTNCallback<OptBTNOrNull<NODE>>>(
1193
+ callback: C = this._DEFAULT_CALLBACK as C,
1271
1194
  beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
1272
1195
  iterationType: IterationType = this.iterationType
1273
- ): OptBTNOrNull<NODE> {
1274
- if (this.isNIL(beginRoot)) return beginRoot as NODE;
1196
+ ): ReturnType<C> {
1197
+ if (this.isNIL(beginRoot)) return callback(undefined);
1275
1198
  // TODO support get right most by passing key in
1276
1199
  beginRoot = this.ensureNode(beginRoot);
1277
- if (!beginRoot) return beginRoot;
1200
+ if (!beginRoot) return callback(beginRoot);
1278
1201
 
1279
1202
  if (iterationType === 'RECURSIVE') {
1280
1203
  const dfs = (cur: NODE): NODE => {
@@ -1282,7 +1205,7 @@ export class BinaryTree<
1282
1205
  return dfs(cur.right);
1283
1206
  };
1284
1207
 
1285
- return dfs(beginRoot);
1208
+ return callback(dfs(beginRoot));
1286
1209
  } else {
1287
1210
  // Indirect implementation of iteration using tail recursion optimization
1288
1211
  const dfs = trampoline((cur: NODE) => {
@@ -1290,15 +1213,10 @@ export class BinaryTree<
1290
1213
  return dfs.cont(cur.right);
1291
1214
  });
1292
1215
 
1293
- return dfs(beginRoot);
1216
+ return callback(dfs(beginRoot));
1294
1217
  }
1295
1218
  }
1296
1219
 
1297
- /**
1298
- * Time Complexity: O(log n)
1299
- * Space Complexity: O(1)
1300
- */
1301
-
1302
1220
  /**
1303
1221
  * Time Complexity: O(log n)
1304
1222
  * Space Complexity: O(1)
@@ -1322,11 +1240,6 @@ export class BinaryTree<
1322
1240
  }
1323
1241
  }
1324
1242
 
1325
- /**
1326
- * Time Complexity: O(log n)
1327
- * Space Complexity: O(1)
1328
- */
1329
-
1330
1243
  /**
1331
1244
  * Time Complexity: O(log n)
1332
1245
  * Space Complexity: O(1)
@@ -1341,7 +1254,7 @@ export class BinaryTree<
1341
1254
  if (!this.isRealNode(x)) return undefined;
1342
1255
 
1343
1256
  if (this.isRealNode(x.right)) {
1344
- return this.getLeftMost(x.right);
1257
+ return this.getLeftMost(node => node, x.right);
1345
1258
  }
1346
1259
 
1347
1260
  let y: OptBTNOrNull<NODE> = x.parent;
@@ -1356,8 +1269,7 @@ export class BinaryTree<
1356
1269
  callback?: C,
1357
1270
  pattern?: DFSOrderPattern,
1358
1271
  beginRoot?: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
1359
- iterationType?: IterationType,
1360
- includeNull?: false
1272
+ iterationType?: IterationType
1361
1273
  ): ReturnType<C>[];
1362
1274
 
1363
1275
  dfs<C extends BTNCallback<NODE | null>>(
@@ -1365,14 +1277,9 @@ export class BinaryTree<
1365
1277
  pattern?: DFSOrderPattern,
1366
1278
  beginRoot?: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
1367
1279
  iterationType?: IterationType,
1368
- includeNull?: true
1280
+ includeNull?: boolean
1369
1281
  ): ReturnType<C>[];
1370
1282
 
1371
- /**
1372
- * Time complexity: O(n)
1373
- * Space complexity: O(n)
1374
- */
1375
-
1376
1283
  /**
1377
1284
  * Time complexity: O(n)
1378
1285
  * Space complexity: O(n)
@@ -1400,95 +1307,12 @@ export class BinaryTree<
1400
1307
  callback: C = this._DEFAULT_CALLBACK as C,
1401
1308
  pattern: DFSOrderPattern = 'IN',
1402
1309
  beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
1403
- iterationType: IterationType = 'ITERATIVE',
1310
+ iterationType: IterationType = this.iterationType,
1404
1311
  includeNull = false
1405
1312
  ): ReturnType<C>[] {
1406
1313
  beginRoot = this.ensureNode(beginRoot);
1407
1314
  if (!beginRoot) return [];
1408
- const ans: ReturnType<C>[] = [];
1409
- if (iterationType === 'RECURSIVE') {
1410
- const dfs = (node: OptBTNOrNull<NODE>) => {
1411
- switch (pattern) {
1412
- case 'IN':
1413
- if (includeNull) {
1414
- if (this.isRealNode(node) && this.isNodeOrNull(node.left)) dfs(node.left);
1415
- this.isNodeOrNull(node) && ans.push(callback(node));
1416
- if (this.isRealNode(node) && this.isNodeOrNull(node.right)) dfs(node.right);
1417
- } else {
1418
- if (this.isRealNode(node) && this.isRealNode(node.left)) dfs(node.left);
1419
- this.isRealNode(node) && ans.push(callback(node));
1420
- if (this.isRealNode(node) && this.isRealNode(node.right)) dfs(node.right);
1421
- }
1422
- break;
1423
- case 'PRE':
1424
- if (includeNull) {
1425
- this.isNodeOrNull(node) && ans.push(callback(node));
1426
- if (this.isRealNode(node) && this.isNodeOrNull(node.left)) dfs(node.left);
1427
- if (this.isRealNode(node) && this.isNodeOrNull(node.right)) dfs(node.right);
1428
- } else {
1429
- this.isRealNode(node) && ans.push(callback(node));
1430
- if (this.isRealNode(node) && this.isRealNode(node.left)) dfs(node.left);
1431
- if (this.isRealNode(node) && this.isRealNode(node.right)) dfs(node.right);
1432
- }
1433
- break;
1434
- case 'POST':
1435
- if (includeNull) {
1436
- if (this.isRealNode(node) && this.isNodeOrNull(node.left)) dfs(node.left);
1437
- if (this.isRealNode(node) && this.isNodeOrNull(node.right)) dfs(node.right);
1438
- this.isNodeOrNull(node) && ans.push(callback(node));
1439
- } else {
1440
- if (this.isRealNode(node) && this.isRealNode(node.left)) dfs(node.left);
1441
- if (this.isRealNode(node) && this.isRealNode(node.right)) dfs(node.right);
1442
- this.isRealNode(node) && ans.push(callback(node));
1443
- }
1444
-
1445
- break;
1446
- }
1447
- };
1448
-
1449
- dfs(beginRoot);
1450
- } else {
1451
- // 0: visit, 1: print
1452
- const stack: { opt: 0 | 1; node: OptBTNOrNull<NODE> }[] = [{ opt: 0, node: beginRoot }];
1453
-
1454
- while (stack.length > 0) {
1455
- const cur = stack.pop();
1456
- if (cur === undefined || this.isNIL(cur.node)) continue;
1457
- if (includeNull) {
1458
- if (cur.node === undefined) continue;
1459
- } else {
1460
- if (cur.node === null || cur.node === undefined) continue;
1461
- }
1462
- if (cur.opt === 1) {
1463
- ans.push(callback(cur.node));
1464
- } else {
1465
- switch (pattern) {
1466
- case 'IN':
1467
- cur.node && stack.push({ opt: 0, node: cur.node.right });
1468
- stack.push({ opt: 1, node: cur.node });
1469
- cur.node && stack.push({ opt: 0, node: cur.node.left });
1470
- break;
1471
- case 'PRE':
1472
- cur.node && stack.push({ opt: 0, node: cur.node.right });
1473
- cur.node && stack.push({ opt: 0, node: cur.node.left });
1474
- stack.push({ opt: 1, node: cur.node });
1475
- break;
1476
- case 'POST':
1477
- stack.push({ opt: 1, node: cur.node });
1478
- cur.node && stack.push({ opt: 0, node: cur.node.right });
1479
- cur.node && stack.push({ opt: 0, node: cur.node.left });
1480
- break;
1481
- default:
1482
- cur.node && stack.push({ opt: 0, node: cur.node.right });
1483
- stack.push({ opt: 1, node: cur.node });
1484
- cur.node && stack.push({ opt: 0, node: cur.node.left });
1485
- break;
1486
- }
1487
- }
1488
- }
1489
- }
1490
-
1491
- return ans;
1315
+ return this._dfs(callback, pattern, beginRoot, iterationType, includeNull);
1492
1316
  }
1493
1317
 
1494
1318
  bfs<C extends BTNCallback<NODE>>(
@@ -1505,11 +1329,6 @@ export class BinaryTree<
1505
1329
  includeNull?: true
1506
1330
  ): ReturnType<C>[];
1507
1331
 
1508
- /**
1509
- * Time complexity: O(n)
1510
- * Space complexity: O(n)
1511
- */
1512
-
1513
1332
  /**
1514
1333
  * Time complexity: O(n)
1515
1334
  * Space complexity: O(n)
@@ -1553,8 +1372,8 @@ export class BinaryTree<
1553
1372
  ans.push(callback(current));
1554
1373
 
1555
1374
  if (includeNull) {
1556
- if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
1557
- if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
1375
+ if (current && this.isRealNodeOrNull(current.left)) queue.push(current.left);
1376
+ if (current && this.isRealNodeOrNull(current.right)) queue.push(current.right);
1558
1377
  } else {
1559
1378
  if (this.isRealNode(current.left)) queue.push(current.left);
1560
1379
  if (this.isRealNode(current.right)) queue.push(current.right);
@@ -1574,8 +1393,8 @@ export class BinaryTree<
1574
1393
  ans.push(callback(current));
1575
1394
 
1576
1395
  if (includeNull) {
1577
- if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
1578
- if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
1396
+ if (current && this.isRealNodeOrNull(current.left)) queue.push(current.left);
1397
+ if (current && this.isRealNodeOrNull(current.right)) queue.push(current.right);
1579
1398
  } else {
1580
1399
  if (this.isRealNode(current.left)) queue.push(current.left);
1581
1400
  if (this.isRealNode(current.right)) queue.push(current.right);
@@ -1586,6 +1405,63 @@ export class BinaryTree<
1586
1405
  return ans;
1587
1406
  }
1588
1407
 
1408
+ /**
1409
+ * Time complexity: O(n)
1410
+ * Space complexity: O(n)
1411
+ *
1412
+ * The `leaves` function in TypeScript iterates through a binary tree to find and return the leaf
1413
+ * nodes based on a specified callback and iteration type.
1414
+ * @param {C} callback - The `callback` parameter is a function that will be called on each leaf node
1415
+ * in the binary tree. It is a generic type `C` that extends `BTNCallback<NODE | null>`, where `NODE`
1416
+ * represents a node in the binary tree. The default value for `callback` is
1417
+ * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter in the `leaves`
1418
+ * method is used to specify the starting point for finding and processing the leaves of a binary
1419
+ * tree. It represents the root node of the binary tree or a specific key, node, or entry within the
1420
+ * tree from which the search for leaves should begin
1421
+ * @param {IterationType} iterationType - The `iterationType` parameter in the `leaves` method
1422
+ * specifies the type of iteration to be performed when collecting the leaves of a binary tree. It
1423
+ * can have two possible values:
1424
+ * @returns The `leaves` method returns an array of values that are the result of applying the
1425
+ * provided callback function to the leaf nodes in the binary tree structure.
1426
+ */
1427
+ leaves<C extends BTNCallback<NODE | null>>(
1428
+ callback: C = this._DEFAULT_CALLBACK as C,
1429
+ beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
1430
+ iterationType: IterationType = this.iterationType
1431
+ ): ReturnType<C>[] {
1432
+ beginRoot = this.ensureNode(beginRoot);
1433
+ const leaves: ReturnType<BTNCallback<NODE>>[] = [];
1434
+ if (!this.isRealNode(beginRoot)) {
1435
+ return [];
1436
+ }
1437
+ if (iterationType === 'RECURSIVE') {
1438
+ const dfs = (cur: NODE) => {
1439
+ if (this.isLeaf(cur)) {
1440
+ leaves.push(callback(cur));
1441
+ }
1442
+ if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
1443
+ this.isRealNode(cur.left) && dfs(cur.left);
1444
+ this.isRealNode(cur.right) && dfs(cur.right);
1445
+ };
1446
+
1447
+ dfs(beginRoot);
1448
+ } else {
1449
+ const queue = new Queue([beginRoot]);
1450
+ while (queue.size > 0) {
1451
+ const cur = queue.shift();
1452
+ if (this.isRealNode(cur)) {
1453
+ if (this.isLeaf(cur)) {
1454
+ leaves.push(callback(cur));
1455
+ }
1456
+ this.isRealNode(cur.left) && queue.push(cur.left);
1457
+ this.isRealNode(cur.right) && queue.push(cur.right);
1458
+ }
1459
+ }
1460
+ }
1461
+
1462
+ return leaves;
1463
+ }
1464
+
1589
1465
  listLevels<C extends BTNCallback<NODE>>(
1590
1466
  callback?: C,
1591
1467
  beginRoot?: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
@@ -1600,11 +1476,6 @@ export class BinaryTree<
1600
1476
  includeNull?: true
1601
1477
  ): ReturnType<C>[][];
1602
1478
 
1603
- /**
1604
- * Time complexity: O(n)
1605
- * Space complexity: O(n)
1606
- */
1607
-
1608
1479
  /**
1609
1480
  * Time complexity: O(n)
1610
1481
  * Space complexity: O(n)
@@ -1641,8 +1512,8 @@ export class BinaryTree<
1641
1512
  if (!levelsNodes[level]) levelsNodes[level] = [];
1642
1513
  levelsNodes[level].push(callback(node));
1643
1514
  if (includeNull) {
1644
- if (node && this.isNodeOrNull(node.left)) _recursive(node.left, level + 1);
1645
- if (node && this.isNodeOrNull(node.right)) _recursive(node.right, level + 1);
1515
+ if (node && this.isRealNodeOrNull(node.left)) _recursive(node.left, level + 1);
1516
+ if (node && this.isRealNodeOrNull(node.right)) _recursive(node.right, level + 1);
1646
1517
  } else {
1647
1518
  if (node && node.left) _recursive(node.left, level + 1);
1648
1519
  if (node && node.right) _recursive(node.right, level + 1);
@@ -1661,8 +1532,8 @@ export class BinaryTree<
1661
1532
  levelsNodes[level].push(callback(node));
1662
1533
 
1663
1534
  if (includeNull) {
1664
- if (node && this.isNodeOrNull(node.right)) stack.push([node.right, level + 1]);
1665
- if (node && this.isNodeOrNull(node.left)) stack.push([node.left, level + 1]);
1535
+ if (node && this.isRealNodeOrNull(node.right)) stack.push([node.right, level + 1]);
1536
+ if (node && this.isRealNodeOrNull(node.left)) stack.push([node.left, level + 1]);
1666
1537
  } else {
1667
1538
  if (node && node.right) stack.push([node.right, level + 1]);
1668
1539
  if (node && node.left) stack.push([node.left, level + 1]);
@@ -1673,11 +1544,6 @@ export class BinaryTree<
1673
1544
  return levelsNodes;
1674
1545
  }
1675
1546
 
1676
- /**
1677
- * Time complexity: O(n)
1678
- * Space complexity: O(n)
1679
- */
1680
-
1681
1547
  /**
1682
1548
  * Time complexity: O(n)
1683
1549
  * Space complexity: O(n)
@@ -1783,11 +1649,6 @@ export class BinaryTree<
1783
1649
  return ans;
1784
1650
  }
1785
1651
 
1786
- /**
1787
- * Time complexity: O(n)
1788
- * Space complexity: O(n)
1789
- */
1790
-
1791
1652
  /**
1792
1653
  * Time complexity: O(n)
1793
1654
  * Space complexity: O(n)
@@ -1809,11 +1670,6 @@ export class BinaryTree<
1809
1670
  return cloned;
1810
1671
  }
1811
1672
 
1812
- /**
1813
- * Time Complexity: O(n)
1814
- * Space Complexity: O(n)
1815
- */
1816
-
1817
1673
  /**
1818
1674
  * Time Complexity: O(n)
1819
1675
  * Space Complexity: O(n)
@@ -1840,11 +1696,6 @@ export class BinaryTree<
1840
1696
  return newTree;
1841
1697
  }
1842
1698
 
1843
- /**
1844
- * Time Complexity: O(n)
1845
- * Space Complexity: O(n)
1846
- */
1847
-
1848
1699
  /**
1849
1700
  * Time Complexity: O(n)
1850
1701
  * Space Complexity: O(n)
@@ -1879,11 +1730,6 @@ export class BinaryTree<
1879
1730
  // // }
1880
1731
  //
1881
1732
 
1882
- /**
1883
- * Time Complexity: O(n)
1884
- * Space Complexity: O(n)
1885
- */
1886
-
1887
1733
  /**
1888
1734
  * Time Complexity: O(n)
1889
1735
  * Space Complexity: O(n)
@@ -1898,35 +1744,185 @@ export class BinaryTree<
1898
1744
  * @returns Nothing is being returned. The function has a return type of `void`, which means it does
1899
1745
  * not return any value.
1900
1746
  */
1901
- override print(beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root, options?: BinaryTreePrintOptions): void {
1747
+ override print(beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root, options?: BinaryTreePrintOptions): string {
1902
1748
  const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1903
1749
  beginRoot = this.ensureNode(beginRoot);
1904
- if (!beginRoot) return;
1750
+ let output = '';
1751
+ if (!beginRoot) return output;
1905
1752
 
1906
1753
  if (opts.isShowUndefined)
1907
- console.log(`U for undefined
1908
- `);
1754
+ output += `U for undefined
1755
+ `;
1909
1756
  if (opts.isShowNull)
1910
- console.log(`N for null
1911
- `);
1757
+ output += `N for null
1758
+ `;
1912
1759
  if (opts.isShowRedBlackNIL)
1913
- console.log(`S for Sentinel Node(NIL)
1914
- `);
1760
+ output += `S for Sentinel Node(NIL)
1761
+ `;
1915
1762
 
1916
1763
  const display = (root: OptBTNOrNull<NODE>): void => {
1917
1764
  const [lines, , ,] = this._displayAux(root, opts);
1765
+ let paragraph = '';
1918
1766
  for (const line of lines) {
1919
- console.log(line);
1767
+ paragraph += line + '\n';
1920
1768
  }
1769
+ output += paragraph;
1921
1770
  };
1922
1771
 
1923
1772
  display(beginRoot);
1773
+ return output;
1924
1774
  }
1925
1775
 
1776
+ protected _dfs<C extends BTNCallback<NODE>>(
1777
+ callback?: C,
1778
+ pattern?: DFSOrderPattern,
1779
+ beginRoot?: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
1780
+ iterationType?: IterationType
1781
+ ): ReturnType<C>[];
1782
+
1783
+ protected _dfs<C extends BTNCallback<NODE | null>>(
1784
+ callback?: C,
1785
+ pattern?: DFSOrderPattern,
1786
+ beginRoot?: R | BTNKeyOrNodeOrEntry<K, V, NODE>,
1787
+ iterationType?: IterationType,
1788
+ includeNull?: boolean
1789
+ ): ReturnType<C>[];
1790
+
1926
1791
  /**
1927
- * Time Complexity: O(1)
1928
- * Space Complexity: O(1)
1929
- */
1792
+ * Time complexity: O(n)
1793
+ * Space complexity: O(n)
1794
+ *
1795
+ * The function `_dfs` performs a depth-first search traversal on a binary tree structure based on
1796
+ * the specified order pattern and callback function.
1797
+ * @param {C} callback - The `callback` parameter is a function that will be called on each node
1798
+ * visited during the depth-first search. It is of type `C`, which extends
1799
+ * `BTNCallback<OptBTNOrNull<NODE>>`. The default value is set to `this._DEFAULT_CALLBACK` if not
1800
+ * provided.
1801
+ * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `_dfs` method specifies the
1802
+ * order in which the Depth-First Search (DFS) algorithm should traverse the nodes in a binary tree.
1803
+ * It can have one of the following values:
1804
+ * @param {R | BTNKeyOrNodeOrEntry<K, V, NODE>} beginRoot - The `beginRoot` parameter in the `_dfs`
1805
+ * method is used to specify the starting point for the depth-first search traversal in a binary
1806
+ * tree. It can be provided as either the root node of the tree or a key, node, or entry that exists
1807
+ * in the tree. If no specific `
1808
+ * @param {IterationType} iterationType - The `iterationType` parameter in the `_dfs` method
1809
+ * specifies the type of iteration to be performed during the Depth-First Search (DFS) traversal. It
1810
+ * can have two possible values:
1811
+ * @param [includeNull=false] - The `includeNull` parameter in the `_dfs` method is a boolean flag
1812
+ * that determines whether null nodes should be included in the depth-first search traversal. If
1813
+ * `includeNull` is set to `true`, the traversal will consider null nodes as valid nodes to visit and
1814
+ * process. If set to `
1815
+ * @param shouldVisitLeft - The `shouldVisitLeft` parameter is a function that takes a node as input
1816
+ * and returns a boolean value. It is used to determine whether the left child of a node should be
1817
+ * visited during the depth-first search traversal. By default, it checks if the node is truthy (not
1818
+ * null or undefined
1819
+ * @param shouldVisitRight - The `shouldVisitRight` parameter is a function that takes a node as
1820
+ * input and returns a boolean value. It is used to determine whether the right child of a node
1821
+ * should be visited during the depth-first search traversal. The default implementation checks if
1822
+ * the node is truthy before visiting the right child.
1823
+ * @param shouldVisitRoot - The `shouldVisitRoot` parameter is a function that takes a node as an
1824
+ * argument and returns a boolean value. It is used to determine whether a given node should be
1825
+ * visited during the depth-first search traversal based on certain conditions. The default
1826
+ * implementation checks if the node is a real node or null based
1827
+ * @param shouldProcessRoot - The `shouldProcessRoot` parameter is a function that takes a node as
1828
+ * input and returns a boolean value indicating whether the node should be processed during the
1829
+ * depth-first search traversal. The default implementation of this function simply returns `true`,
1830
+ * meaning that by default all nodes will be processed. However, you can
1831
+ * @returns The `_dfs` method returns an array of the return type of the callback function provided
1832
+ * as input.
1833
+ */
1834
+ protected _dfs<C extends BTNCallback<OptBTNOrNull<NODE>>>(
1835
+ callback: C = this._DEFAULT_CALLBACK as C,
1836
+ pattern: DFSOrderPattern = 'IN',
1837
+ beginRoot: R | BTNKeyOrNodeOrEntry<K, V, NODE> = this.root,
1838
+ iterationType: IterationType = this.iterationType,
1839
+ includeNull = false,
1840
+ shouldVisitLeft: (node: OptBTNOrNull<NODE>) => boolean = node => !!node,
1841
+ shouldVisitRight: (node: OptBTNOrNull<NODE>) => boolean = node => !!node,
1842
+ shouldVisitRoot: (node: OptBTNOrNull<NODE>) => boolean = node => {
1843
+ if (includeNull) return this.isRealNodeOrNull(node);
1844
+ return this.isRealNode(node);
1845
+ },
1846
+ shouldProcessRoot: (node: OptBTNOrNull<NODE>) => boolean = node => true
1847
+ ): ReturnType<C>[] {
1848
+ beginRoot = this.ensureNode(beginRoot);
1849
+ if (!beginRoot) return [];
1850
+ const ans: ReturnType<C>[] = [];
1851
+
1852
+ if (iterationType === 'RECURSIVE') {
1853
+ const dfs = (node: OptBTNOrNull<NODE>) => {
1854
+ if (!shouldVisitRoot(node)) return;
1855
+
1856
+ const visitLeft = () => {
1857
+ if (shouldVisitLeft(node)) dfs(node?.left);
1858
+ };
1859
+ const visitRight = () => {
1860
+ if (shouldVisitRight(node)) dfs(node?.right);
1861
+ };
1862
+
1863
+ switch (pattern) {
1864
+ case 'IN':
1865
+ visitLeft();
1866
+ if (shouldProcessRoot(node)) ans.push(callback(node));
1867
+ visitRight();
1868
+ break;
1869
+ case 'PRE':
1870
+ if (shouldProcessRoot(node)) ans.push(callback(node));
1871
+ visitLeft();
1872
+ visitRight();
1873
+ break;
1874
+ case 'POST':
1875
+ visitLeft();
1876
+ visitRight();
1877
+ if (shouldProcessRoot(node)) ans.push(callback(node));
1878
+ break;
1879
+ }
1880
+ };
1881
+
1882
+ dfs(beginRoot);
1883
+ } else {
1884
+ const stack: DFSStackItem<NODE>[] = [{ opt: DFSOperation.VISIT, node: beginRoot }];
1885
+
1886
+ const pushLeft = (cur: DFSStackItem<NODE>) => {
1887
+ if (shouldVisitLeft(cur.node)) stack.push({ opt: DFSOperation.VISIT, node: cur.node?.left });
1888
+ };
1889
+ const pushRight = (cur: DFSStackItem<NODE>) => {
1890
+ if (shouldVisitRight(cur.node)) stack.push({ opt: DFSOperation.VISIT, node: cur.node?.right });
1891
+ };
1892
+ const pushRoot = (cur: DFSStackItem<NODE>) => {
1893
+ if (shouldVisitRoot(cur.node)) stack.push({ opt: DFSOperation.PROCESS, node: cur.node });
1894
+ };
1895
+
1896
+ while (stack.length > 0) {
1897
+ const cur = stack.pop();
1898
+ if (cur === undefined) continue;
1899
+ if (!shouldVisitRoot(cur.node)) continue;
1900
+ if (cur.opt === DFSOperation.PROCESS) {
1901
+ if (shouldProcessRoot(cur.node)) ans.push(callback(cur.node));
1902
+ } else {
1903
+ switch (pattern) {
1904
+ case 'IN':
1905
+ pushRight(cur);
1906
+ pushRoot(cur);
1907
+ pushLeft(cur);
1908
+ break;
1909
+ case 'PRE':
1910
+ pushRight(cur);
1911
+ pushLeft(cur);
1912
+ pushRoot(cur);
1913
+ break;
1914
+ case 'POST':
1915
+ pushRoot(cur);
1916
+ pushRight(cur);
1917
+ pushLeft(cur);
1918
+ break;
1919
+ }
1920
+ }
1921
+ }
1922
+ }
1923
+
1924
+ return ans;
1925
+ }
1930
1926
 
1931
1927
  /**
1932
1928
  * Time Complexity: O(1)
@@ -1969,11 +1965,6 @@ export class BinaryTree<
1969
1965
  }
1970
1966
  }
1971
1967
 
1972
- /**
1973
- * Time Complexity: O(n)
1974
- * Space Complexity: O(n)
1975
- */
1976
-
1977
1968
  /**
1978
1969
  * Time Complexity: O(n)
1979
1970
  * Space Complexity: O(n)
@@ -2061,11 +2052,6 @@ export class BinaryTree<
2061
2052
 
2062
2053
  protected _DEFAULT_CALLBACK = (node: OptBTNOrNull<NODE>) => (node ? node.key : undefined);
2063
2054
 
2064
- /**
2065
- * Time Complexity: O(1)
2066
- * Space Complexity: O(1)
2067
- */
2068
-
2069
2055
  /**
2070
2056
  * Time Complexity: O(1)
2071
2057
  * Space Complexity: O(1)
@@ -2103,11 +2089,6 @@ export class BinaryTree<
2103
2089
  return undefined;
2104
2090
  }
2105
2091
 
2106
- /**
2107
- * Time Complexity: O(1)
2108
- * Space Complexity: O(1)
2109
- */
2110
-
2111
2092
  /**
2112
2093
  * Time Complexity: O(1)
2113
2094
  * Space Complexity: O(1)
@@ -2138,11 +2119,6 @@ export class BinaryTree<
2138
2119
  return newNode;
2139
2120
  }
2140
2121
 
2141
- /**
2142
- * Time Complexity: O(1)
2143
- * Space Complexity: O(1)
2144
- */
2145
-
2146
2122
  /**
2147
2123
  * Time Complexity: O(1)
2148
2124
  * Space Complexity: O(1)
@@ -2159,11 +2135,6 @@ export class BinaryTree<
2159
2135
  this._root = v;
2160
2136
  }
2161
2137
 
2162
- /**
2163
- * Time Complexity: O(1)
2164
- * Space Complexity: O(1)
2165
- */
2166
-
2167
2138
  /**
2168
2139
  * Time Complexity: O(1)
2169
2140
  * Space Complexity: O(1)