data-structure-typed 1.37.0 → 1.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,19 +7,19 @@
7
7
  */
8
8
 
9
9
  import type {
10
+ BFSCallback,
11
+ BFSCallbackReturn,
10
12
  BinaryTreeNodeKey,
11
13
  BinaryTreeNodeNested,
12
- BinaryTreeNodeProperties,
13
- BinaryTreeNodeProperty,
14
- BinaryTreeOptions
14
+ BinaryTreeOptions,
15
+ MapCallback,
16
+ MapCallbackReturn
15
17
  } from '../../types';
16
18
  import {
17
19
  BinaryTreeDeletedResult,
18
- BinaryTreeNodePropertyName,
19
20
  DFSOrderPattern,
20
21
  FamilyPosition,
21
- LoopType,
22
- NodeOrPropertyName
22
+ LoopType
23
23
  } from '../../types';
24
24
  import {IBinaryTree} from '../../interfaces';
25
25
  import {trampoline} from '../../utils';
@@ -127,6 +127,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
127
127
  createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
128
128
  return new BinaryTreeNode<N['val'], N>(key, val) as N;
129
129
  }
130
+
130
131
  // TODO placeholder node may need redesigned
131
132
  private _root: N | null = null;
132
133
 
@@ -150,12 +151,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
150
151
  this._loopType = v;
151
152
  }
152
153
 
153
- visitedKey: BinaryTreeNodeKey[] = [];
154
-
155
- visitedVal: N['val'][] = [];
156
-
157
- visitedNode: N[] = [];
158
-
159
154
  /**
160
155
  * The `_swap` function swaps the location of two nodes in a binary tree.
161
156
  * @param {N} srcNode - The source node that you want to _swap with the destination node.
@@ -184,7 +179,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
184
179
  clear() {
185
180
  this._root = null;
186
181
  this._size = 0;
187
- this._clearResults();
188
182
  }
189
183
 
190
184
  /**
@@ -237,7 +231,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
237
231
  return;
238
232
  }
239
233
 
240
- const existNode = keyOrNode ? this.get(keyOrNode, 'key') : undefined;
234
+ const existNode = keyOrNode ? this.get(keyOrNode, this._defaultCallbackByKey) : undefined;
241
235
 
242
236
  if (this.root) {
243
237
  if (existNode) {
@@ -360,8 +354,8 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
360
354
  * @returns the depth of the given node or binary tree.
361
355
  */
362
356
  getDepth(distNode: N | BinaryTreeNodeKey | null, beginRoot: N | BinaryTreeNodeKey | null = this.root): number {
363
- if (typeof distNode === 'number') distNode = this.get(distNode, 'key');
364
- if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
357
+ if (typeof distNode === 'number') distNode = this.get(distNode);
358
+ if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
365
359
  let depth = 0;
366
360
  while (distNode?.parent) {
367
361
  if (distNode === beginRoot) {
@@ -381,7 +375,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
381
375
  * @returns the height of the binary tree.
382
376
  */
383
377
  getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root): number {
384
- if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
378
+ if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
385
379
  if (!beginRoot) return -1;
386
380
 
387
381
  if (this._loopType === LoopType.RECURSIVE) {
@@ -419,6 +413,8 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
419
413
  }
420
414
  }
421
415
 
416
+ protected _defaultCallbackByKey: MapCallback<N> = node => node.key;
417
+
422
418
  /**
423
419
  * The `getMinHeight` function calculates the minimum height of a binary tree using either a recursive or iterative
424
420
  * approach.
@@ -482,125 +478,108 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
482
478
 
483
479
  /**
484
480
  * The function `getNodes` returns an array of nodes that match a given property name and value in a binary tree.
481
+ * @param callback
485
482
  * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
486
483
  * generic type `N`. It represents the property of the binary tree node that you want to search for.
487
- * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
488
484
  * specifies the property name to use when searching for nodes. If not provided, it defaults to 'key'.
489
485
  * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
490
486
  * return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the
491
487
  * function will stop traversing the tree and return the first matching node. If `only
488
+ * @param beginRoot
492
489
  * @returns an array of nodes (type N).
493
490
  */
494
491
  getNodes(
495
492
  nodeProperty: BinaryTreeNodeKey | N,
496
- propertyName: BinaryTreeNodePropertyName = 'key',
497
- onlyOne = false
493
+ callback: MapCallback<N> = this._defaultCallbackByKey,
494
+ onlyOne = false,
495
+ beginRoot: N | null = this.root
498
496
  ): N[] {
499
- if (!this.root) return [];
497
+ if (!beginRoot) return [];
500
498
 
501
- const result: N[] = [];
499
+ const ans: N[] = [];
502
500
 
503
501
  if (this.loopType === LoopType.RECURSIVE) {
504
502
  const _traverse = (cur: N) => {
505
- if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return;
503
+ if (callback(cur) === nodeProperty) {
504
+ ans.push(cur);
505
+ if (onlyOne) return;
506
+ }
506
507
  if (!cur.left && !cur.right) return;
507
508
  cur.left && _traverse(cur.left);
508
509
  cur.right && _traverse(cur.right);
509
510
  };
510
511
 
511
- _traverse(this.root);
512
+ _traverse(beginRoot);
512
513
  } else {
513
- const queue = new Queue<N>([this.root]);
514
+ const queue = new Queue<N>([beginRoot]);
514
515
  while (queue.size > 0) {
515
516
  const cur = queue.shift();
516
517
  if (cur) {
517
- if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result;
518
+ if (callback(cur) === nodeProperty) {
519
+ ans.push(cur);
520
+ if (onlyOne) return ans;
521
+ }
518
522
  cur.left && queue.push(cur.left);
519
523
  cur.right && queue.push(cur.right);
520
524
  }
521
525
  }
522
526
  }
523
527
 
524
- return result;
528
+ return ans;
525
529
  }
526
530
 
527
531
  /**
528
532
  * The function checks if a binary tree node has a specific property.
533
+ * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
529
534
  * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`.
530
535
  * It represents the property of the binary tree node that you want to check.
531
- * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
532
536
  * specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'.
533
537
  * @returns a boolean value.
534
538
  */
535
- has(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): boolean {
539
+ has(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback<N> = this._defaultCallbackByKey): boolean {
536
540
  // TODO may support finding node by value equal
537
- return this.getNodes(nodeProperty, propertyName).length > 0;
541
+ return this.getNodes(nodeProperty, callback, true).length > 0;
538
542
  }
539
543
 
540
544
  /**
541
545
  * The function returns the first node that matches the given property name and value, or null if no matching node is
542
546
  * found.
547
+ * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
543
548
  * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`.
544
549
  * It represents the property of the binary tree node that you want to search for.
545
- * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
546
550
  * specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the
547
551
  * default value is set to `'key'`.
548
552
  * @returns either the value of the specified property of the node, or the node itself if no property name is provided.
549
553
  * If no matching node is found, it returns null.
550
554
  */
551
- get(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): N | null {
555
+ get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback<N> = this._defaultCallbackByKey): N | null {
552
556
  // TODO may support finding node by value equal
553
- return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
557
+ return this.getNodes(nodeProperty, callback, true)[0] ?? null;
554
558
  }
555
559
 
556
560
  /**
557
561
  * The function `getPathToRoot` returns an array of nodes representing the path from a given node to the root node, with
558
562
  * an option to reverse the order of the nodes.
559
- * @param {N} node - The `node` parameter represents a node in a tree structure. It is of type `N`, which could be any
560
563
  * type that represents a node in your specific implementation.
564
+ * @param beginRoot - The `beginRoot` parameter is of type `N` and represents the starting node from which you want to
561
565
  * @param {boolean} [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the resulting
562
566
  * path should be reversed or not. If `isReverse` is set to `true`, the path will be reversed before returning it. If
563
567
  * `isReverse` is set to `false` or not provided, the path will
564
568
  * @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
565
569
  */
566
- getPathToRoot(node: N, isReverse = true): N[] {
570
+ getPathToRoot(beginRoot: N, isReverse = true): N[] {
567
571
  // TODO to support get path through passing key
568
572
  const result: N[] = [];
569
- while (node.parent) {
573
+ while (beginRoot.parent) {
570
574
  // Array.push + Array.reverse is more efficient than Array.unshift
571
575
  // TODO may consider using Deque, so far this is not the performance bottleneck
572
- result.push(node);
573
- node = node.parent;
576
+ result.push(beginRoot);
577
+ beginRoot = beginRoot.parent;
574
578
  }
575
- result.push(node);
579
+ result.push(beginRoot);
576
580
  return isReverse ? result.reverse() : result;
577
581
  }
578
582
 
579
- /**
580
- * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
581
- * no node is specified.
582
- * generic type representing a node in a binary tree, `BinaryTreeNodeKey` (a type representing the ID of a binary tree
583
- * node), or `null`.
584
- * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
585
- * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
586
- * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost
587
- * node is found (
588
- */
589
- getLeftMost(): N | null;
590
-
591
- /**
592
- * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
593
- * no node is specified.
594
- * @param {N | BinaryTreeNodeKey | null} [node] - The `beginRoot` parameter is optional and can be of type `N` (a
595
- * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
596
- * node).
597
- * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
598
- * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
599
- * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost
600
- * node is found (
601
- */
602
- getLeftMost(node: N): N;
603
-
604
583
  /**
605
584
  * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if
606
585
  * no node is specified.
@@ -613,7 +592,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
613
592
  * node is found (
614
593
  */
615
594
  getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root): N | null {
616
- if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key');
595
+ if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
617
596
 
618
597
  if (!beginRoot) return beginRoot;
619
598
 
@@ -635,25 +614,6 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
635
614
  }
636
615
  }
637
616
 
638
- /**
639
- * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail
640
- * recursion optimization.
641
- * @returns The `getRightMost` function returns the rightmost node in a binary tree. It returns the
642
- * rightmost node starting from the root of the binary tree.
643
- */
644
- getRightMost(): N | null;
645
-
646
- /**
647
- * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail
648
- * recursion optimization.
649
- * @param {N | null} [beginRoot] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the
650
- * starting node from which we want to find the rightmost node. If no node is provided, the function will default to
651
- * using the root node of the data structure.
652
- * @returns The `getRightMost` function returns the rightmost node in a binary tree. It returns the rightmost node
653
- * starting from that node.
654
- */
655
- getRightMost(beginRoot: N): N;
656
-
657
617
  /**
658
618
  * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail
659
619
  * recursion optimization.
@@ -730,55 +690,25 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
730
690
  }
731
691
 
732
692
  /**
733
- * The function calculates the size of a subtree by traversing it either recursively or iteratively.
734
- * @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a
735
- * binary tree.
736
- * @returns the size of the subtree rooted at `subTreeRoot`.
737
- */
738
- getSubTreeSize(subTreeRoot: N | null | undefined) {
739
- // TODO support key passed in
740
- let size = 0;
741
- if (!subTreeRoot) return size;
742
-
743
- if (this._loopType === LoopType.RECURSIVE) {
744
- const _traverse = (cur: N) => {
745
- size++;
746
- cur.left && _traverse(cur.left);
747
- cur.right && _traverse(cur.right);
748
- };
749
-
750
- _traverse(subTreeRoot);
751
- return size;
752
- } else {
753
- const stack: N[] = [subTreeRoot];
754
-
755
- while (stack.length > 0) {
756
- const cur = stack.pop()!;
757
- size++;
758
- cur.right && stack.push(cur.right);
759
- cur.left && stack.push(cur.left);
760
- }
761
-
762
- return size;
763
- }
764
- }
765
-
766
- /**
767
- * The function `subTreeForeach` adds a delta value to a specified property of each node in a subtree.
693
+ * The function `subTreeTraverse` adds a delta value to a specified property of each node in a subtree.
768
694
  * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
769
695
  * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to.
770
696
  * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
771
697
  * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'.
772
698
  * @returns a boolean value.
773
699
  */
774
- subTreeForeach(subTreeRoot: N | BinaryTreeNodeKey | null, callback: (node: N) => any): boolean {
775
- if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
700
+ subTreeTraverse(
701
+ callback: MapCallback<N> = this._defaultCallbackByKey,
702
+ subTreeRoot: N | BinaryTreeNodeKey | null = this.root
703
+ ): MapCallbackReturn<N>[] {
704
+ if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot);
776
705
 
777
- if (!subTreeRoot) return false;
706
+ const ans: MapCallbackReturn<N>[] = [];
707
+ if (!subTreeRoot) return ans;
778
708
 
779
709
  if (this._loopType === LoopType.RECURSIVE) {
780
710
  const _traverse = (cur: N) => {
781
- callback(cur);
711
+ ans.push(callback(cur));
782
712
  cur.left && _traverse(cur.left);
783
713
  cur.right && _traverse(cur.right);
784
714
  };
@@ -790,150 +720,64 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
790
720
  while (stack.length > 0) {
791
721
  const cur = stack.pop()!;
792
722
 
793
- callback(cur);
723
+ ans.push(callback(cur));
794
724
  cur.right && stack.push(cur.right);
795
725
  cur.left && stack.push(cur.left);
796
726
  }
797
727
  }
798
- return true;
799
- }
800
-
801
- /**
802
- * Performs a breadth-first search (bfs) on a binary tree, accumulating properties of each node based on their 'key' property.
803
- * @returns An array of binary tree node IDs.
804
- */
805
- bfs(): BinaryTreeNodeKey[];
806
-
807
- /**
808
- * Performs a breadth-first search (bfs) on a binary tree, accumulating properties of each node based on the specified property name.
809
- * @param {'key'} nodeOrPropertyName - The name of the property to accumulate.
810
- * @returns An array of values corresponding to the specified property.
811
- */
812
- bfs(nodeOrPropertyName: 'key'): BinaryTreeNodeKey[];
813
-
814
- /**
815
- * Performs a breadth-first search (bfs) on a binary tree, accumulating the 'val' property of each node.
816
- * @param {'val'} nodeOrPropertyName - The name of the property to accumulate.
817
- * @returns An array of 'val' properties from each node.
818
- */
819
- bfs(nodeOrPropertyName: 'val'): N['val'][];
820
-
821
- /**
822
- * Performs a breadth-first search (bfs) on a binary tree, accumulating nodes themselves.
823
- * @param {'node'} nodeOrPropertyName - The name of the property to accumulate.
824
- * @returns An array of binary tree nodes.
825
- */
826
- bfs(nodeOrPropertyName: 'node'): N[];
827
-
828
- /**
829
- * The bfs function performs a breadth-first search on a binary tree, accumulating properties of each node based on a specified property name.
830
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - An optional parameter that represents either a node or a property name.
831
- * If a node is provided, the bfs algorithm will be performed starting from that node.
832
- * If a property name is provided, the bfs algorithm will be performed starting from the root node, accumulating the specified property.
833
- * @returns An instance of the `BinaryTreeNodeProperties` class with generic type `N`.
834
- */
835
- bfs(nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties<N> {
836
- this._clearResults();
837
- const queue = new Queue<N | null | undefined>([this.root]);
838
-
839
- while (queue.size !== 0) {
840
- const cur = queue.shift();
841
- if (cur) {
842
- this._accumulatedByPropertyName(cur, nodeOrPropertyName);
843
- if (cur?.left !== null) queue.push(cur.left);
844
- if (cur?.right !== null) queue.push(cur.right);
845
- }
846
- }
847
-
848
- return this._getResultByPropertyName(nodeOrPropertyName);
728
+ return ans;
849
729
  }
850
730
 
851
- /**
852
- * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on their 'key' property.
853
- * @returns An array of binary tree node IDs.
854
- */
855
- dfs(): BinaryTreeNodeKey[];
856
-
857
- /**
858
- * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name.
859
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
860
- * @returns An array of values corresponding to the specified property.
861
- */
862
- dfs(pattern: DFSOrderPattern): BinaryTreeNodeKey[];
863
-
864
- /**
865
- * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name.
866
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
867
- * @param {string} nodeOrPropertyName - The name of the property to accumulate.
868
- * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`.
869
- * @returns An array of values corresponding to the specified property.
870
- */
871
- dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'key', loopType?: LoopType): BinaryTreeNodeKey[];
872
-
873
- /**
874
- * Performs a depth-first search (dfs) traversal on a binary tree and accumulates the 'val' property of each node.
875
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
876
- * @param {'val'} nodeOrPropertyName - The name of the property to accumulate.
877
- * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`.
878
- * @returns An array of 'val' properties from each node.
879
- */
880
- dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'val', loopType?: LoopType): N[];
881
-
882
- /**
883
- * Performs a depth-first search (dfs) traversal on a binary tree and accumulates nodes themselves.
884
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
885
- * @param {'node'} nodeOrPropertyName - The name of the property to accumulate.
886
- * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`.
887
- * @returns An array of binary tree nodes.
888
- */
889
- dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'node', loopType?: LoopType): N[];
890
-
891
731
  /**
892
732
  * The dfs function performs a depth-first search traversal on a binary tree and returns the accumulated properties of
893
733
  * each node based on the specified pattern and property name.
734
+ * @param callback
735
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the
894
736
  * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
895
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. If no `nodeOrPropertyName` is provided, the default value is `'key'`.
896
737
  * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`.
897
738
  * @returns an instance of the BinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name.
898
739
  */
899
740
  dfs(
741
+ callback: MapCallback<N> = this._defaultCallbackByKey,
900
742
  pattern: DFSOrderPattern = 'in',
901
- nodeOrPropertyName: NodeOrPropertyName = 'key',
743
+ beginRoot: N | null = this.root,
902
744
  loopType: LoopType = LoopType.ITERATIVE
903
- ): BinaryTreeNodeProperties<N> {
904
- this._clearResults();
745
+ ): MapCallbackReturn<N>[] {
746
+ if (!beginRoot) return [];
747
+ const ans: MapCallbackReturn<N>[] = [];
905
748
  if (loopType === LoopType.RECURSIVE) {
906
749
  const _traverse = (node: N) => {
907
750
  switch (pattern) {
908
751
  case 'in':
909
752
  if (node.left) _traverse(node.left);
910
- this._accumulatedByPropertyName(node, nodeOrPropertyName);
753
+ ans.push(callback(node));
911
754
  if (node.right) _traverse(node.right);
912
755
  break;
913
756
  case 'pre':
914
- this._accumulatedByPropertyName(node, nodeOrPropertyName);
757
+ ans.push(callback(node));
758
+
915
759
  if (node.left) _traverse(node.left);
916
760
  if (node.right) _traverse(node.right);
917
761
  break;
918
762
  case 'post':
919
763
  if (node.left) _traverse(node.left);
920
764
  if (node.right) _traverse(node.right);
921
- this._accumulatedByPropertyName(node, nodeOrPropertyName);
765
+ ans.push(callback(node));
766
+
922
767
  break;
923
768
  }
924
769
  };
925
770
 
926
- this.root && _traverse(this.root);
771
+ _traverse(beginRoot);
927
772
  } else {
928
- if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName);
929
773
  // 0: visit, 1: print
930
- const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: this.root}];
774
+ const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}];
931
775
 
932
776
  while (stack.length > 0) {
933
777
  const cur = stack.pop();
934
778
  if (!cur || !cur.node) continue;
935
779
  if (cur.opt === 1) {
936
- this._accumulatedByPropertyName(cur.node, nodeOrPropertyName);
780
+ ans.push(callback(cur.node));
937
781
  } else {
938
782
  switch (pattern) {
939
783
  case 'in':
@@ -961,83 +805,30 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
961
805
  }
962
806
  }
963
807
 
964
- return this._getResultByPropertyName(nodeOrPropertyName);
808
+ return ans;
965
809
  }
966
810
 
967
811
  // --- start additional methods ---
968
812
 
969
- /**
970
- * Collects nodes from a binary tree by a specified property and organizes them into levels.
971
- * @returns A 2D array of AbstractBinaryTreeNodeProperty<N> objects.
972
- */
973
- listLevels(): BinaryTreeNodeKey[][];
974
-
975
- /**
976
- * Collects nodes from a binary tree by a specified property and organizes them into levels.
977
- * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
978
- * @returns A 2D array of AbstractBinaryTreeNodeProperty<N> objects.
979
- */
980
- listLevels(node: N | null): BinaryTreeNodeKey[][];
981
-
982
- /**
983
- * Collects nodes from a binary tree by a specified property and organizes them into levels.
984
- * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
985
- * @param {'key} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
986
- * @returns A 2D array of values corresponding to the specified property.
987
- */
988
- listLevels(node: N | null, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[][];
989
-
990
- /**
991
- * Collects nodes from a binary tree by a specified property and organizes them into levels.
992
- * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
993
- * @param {'val'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
994
- * @returns A 2D array of 'val' properties from each node.
995
- */
996
- listLevels(node: N | null, nodeOrPropertyName: 'val'): N['val'][][];
997
-
998
- /**
999
- * Collects nodes from a binary tree by a specified property and organizes them into levels.
1000
- * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance.
1001
- * @param {'node'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
1002
- * @returns A 2D array of binary tree nodes.
1003
- */
1004
- listLevels(node: N | null, nodeOrPropertyName: 'node'): N[][];
1005
-
1006
813
  /**
1007
814
  * The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels.
1008
815
  * @param {N | null} node - The `node` parameter is a BinaryTreeNode object or null. It represents the root node of a binary tree. If it is null, the function will use the root node of the current binary tree instance.
1009
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that specifies the property of the `BinaryTreeNode` object to collect at each level. It can be one of the following values: 'key', 'val', or 'node'. If not provided, it defaults to 'key'.
1010
- * @returns A 2D array of `AbstractBinaryTreeNodeProperty<N>` objects.
1011
- */
1012
- listLevels(
1013
- node: N | null = this.root,
1014
- nodeOrPropertyName: NodeOrPropertyName = 'key'
1015
- ): BinaryTreeNodeProperty<N>[][] {
816
+ * @param callback - The `callback` parameter is a function that takes a node and a level as parameters and returns a value.
817
+ * @param withLevel - The `withLevel` parameter is a boolean flag that determines whether to include the level of each node in the result. If `withLevel` is set to `true`, the function will include the level of each node in the result. If `withLevel` is set to `false` or not provided, the function will not include the level of each node in the result.
818
+ */
819
+ bfs(
820
+ callback: BFSCallback<N> = this._defaultCallbackByKey,
821
+ withLevel: boolean = false,
822
+ node?: N | null
823
+ ): BFSCallbackReturn<N>[] {
824
+ if (!node) node = this.root;
1016
825
  if (!node) return [];
1017
826
 
1018
- const levelsNodes: BinaryTreeNodeProperty<N>[][] = [];
1019
-
1020
- const collectByProperty = (node: N, level: number) => {
1021
- switch (nodeOrPropertyName) {
1022
- case 'key':
1023
- levelsNodes[level].push(node.key);
1024
- break;
1025
- case 'val':
1026
- levelsNodes[level].push(node.val);
1027
- break;
1028
- case 'node':
1029
- levelsNodes[level].push(node);
1030
- break;
1031
- default:
1032
- levelsNodes[level].push(node.key);
1033
- break;
1034
- }
1035
- };
827
+ const ans: BFSCallbackReturn<N>[] = [];
1036
828
 
1037
829
  if (this.loopType === LoopType.RECURSIVE) {
1038
830
  const _recursive = (node: N, level: number) => {
1039
- if (!levelsNodes[level]) levelsNodes[level] = [];
1040
- collectByProperty(node, level);
831
+ callback && ans.push(callback(node, withLevel ? level : undefined));
1041
832
  if (node.left) _recursive(node.left, level + 1);
1042
833
  if (node.right) _recursive(node.right, level + 1);
1043
834
  };
@@ -1050,14 +841,12 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1050
841
  const head = stack.pop()!;
1051
842
  const [node, level] = head;
1052
843
 
1053
- if (!levelsNodes[level]) levelsNodes[level] = [];
1054
- collectByProperty(node, level);
844
+ callback && ans.push(callback(node, withLevel ? level : undefined));
1055
845
  if (node.right) stack.push([node.right, level + 1]);
1056
846
  if (node.left) stack.push([node.left, level + 1]);
1057
847
  }
1058
848
  }
1059
-
1060
- return levelsNodes;
849
+ return ans;
1061
850
  }
1062
851
 
1063
852
  /**
@@ -1084,53 +873,18 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1084
873
  * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack
1085
874
  */
1086
875
 
1087
- /**
1088
- * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm.
1089
- * @returns An array of binary tree node IDs.
1090
- */
1091
- morris(): BinaryTreeNodeKey[];
1092
-
1093
- /**
1094
- * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates properties of each node based on the specified property name.
1095
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
1096
- * @param {'key'} nodeOrPropertyName - The name of the property to accumulate.
1097
- * @returns An array of values corresponding to the specified property.
1098
- */
1099
- morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[];
1100
-
1101
- /**
1102
- * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates properties of each node based on the specified property name.
1103
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
1104
- * @returns An array of values corresponding to the specified property.
1105
- */
1106
- morris(pattern: DFSOrderPattern): BinaryTreeNodeKey[];
1107
-
1108
- /**
1109
- * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates the 'val' property of each node.
1110
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
1111
- * @param {'val'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
1112
- * @returns An array of 'val' properties from each node.
1113
- */
1114
- morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'val'): N[];
1115
-
1116
- /**
1117
- * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates nodes themselves.
1118
- * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
1119
- * @param {'node'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level.
1120
- * @returns An array of binary tree nodes.
1121
- */
1122
- morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'node'): N[];
1123
-
1124
876
  /**
1125
877
  * The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm.
1126
878
  * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
1127
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - The property name of the nodes to retrieve or perform operations on during the traversal. It can be any valid property name of the nodes in the binary tree. If not provided, it defaults to 'key'.
879
+ * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
1128
880
  * @returns An array of BinaryTreeNodeProperties<N> objects.
1129
881
  */
1130
- morris(pattern: DFSOrderPattern = 'in', nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties<N> {
882
+ morris(
883
+ callback: MapCallback<N> = this._defaultCallbackByKey,
884
+ pattern: DFSOrderPattern = 'in'
885
+ ): MapCallbackReturn<N>[] {
1131
886
  if (this.root === null) return [];
1132
-
1133
- this._clearResults();
887
+ const ans: MapCallbackReturn<N>[] = [];
1134
888
 
1135
889
  let cur: N | null | undefined = this.root;
1136
890
  const _reverseEdge = (node: N | null | undefined) => {
@@ -1148,7 +902,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1148
902
  const tail: N | null | undefined = _reverseEdge(node);
1149
903
  let cur: N | null | undefined = tail;
1150
904
  while (cur) {
1151
- this._accumulatedByPropertyName(cur, nodeOrPropertyName);
905
+ ans.push(callback(cur));
1152
906
  cur = cur.right;
1153
907
  }
1154
908
  _reverseEdge(tail);
@@ -1166,7 +920,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1166
920
  predecessor.right = null;
1167
921
  }
1168
922
  }
1169
- this._accumulatedByPropertyName(cur, nodeOrPropertyName);
923
+ ans.push(callback(cur));
1170
924
  cur = cur.right;
1171
925
  }
1172
926
  break;
@@ -1176,14 +930,14 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1176
930
  const predecessor = this.getPredecessor(cur);
1177
931
  if (!predecessor.right) {
1178
932
  predecessor.right = cur;
1179
- this._accumulatedByPropertyName(cur, nodeOrPropertyName);
933
+ ans.push(callback(cur));
1180
934
  cur = cur.left;
1181
935
  continue;
1182
936
  } else {
1183
937
  predecessor.right = null;
1184
938
  }
1185
939
  } else {
1186
- this._accumulatedByPropertyName(cur, nodeOrPropertyName);
940
+ ans.push(callback(cur));
1187
941
  }
1188
942
  cur = cur.right;
1189
943
  }
@@ -1206,8 +960,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1206
960
  _printEdge(this.root);
1207
961
  break;
1208
962
  }
1209
-
1210
- return this._getResultByPropertyName(nodeOrPropertyName);
963
+ return ans;
1211
964
  }
1212
965
 
1213
966
  /**
@@ -1264,108 +1017,5 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
1264
1017
  this._size = v;
1265
1018
  }
1266
1019
 
1267
- /**
1268
- * The function `_clearResults` resets the values of several arrays used for tracking visited nodes and their
1269
- * properties.
1270
- */
1271
- protected _clearResults() {
1272
- this.visitedKey = [];
1273
- this.visitedVal = [];
1274
- this.visitedNode = [];
1275
- }
1276
-
1277
- /**
1278
- * The function checks if a given property of a binary tree node matches a specified value, and if so, adds the node to
1279
- * a result array.
1280
- * @param {N} cur - The current node being processed.
1281
- * @param {(N | null | undefined)[]} result - An array that stores the matching nodes.
1282
- * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is either a `BinaryTreeNodeKey` or a `N`
1283
- * type. It represents the property value that we are comparing against in the switch statement.
1284
- * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
1285
- * specifies the property name to compare against when pushing nodes into the `result` array. It can be either `'key'`
1286
- * or `'val'`. If it is not provided or is not equal to `'key'` or `'val'`, the
1287
- * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
1288
- * stop after finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set to
1289
- * `true`, the function will stop after finding the first matching node and return `true`. If `onlyOne
1290
- * @returns a boolean value indicating whether only one matching node should be pushed into the result array.
1291
- */
1292
- protected _pushByPropertyNameStopOrNot(
1293
- cur: N,
1294
- result: (N | null | undefined)[],
1295
- nodeProperty: BinaryTreeNodeKey | N,
1296
- propertyName: BinaryTreeNodePropertyName = 'key',
1297
- onlyOne = false
1298
- ) {
1299
- switch (propertyName) {
1300
- case 'key':
1301
- if (cur.key === nodeProperty) {
1302
- result.push(cur);
1303
- return onlyOne;
1304
- }
1305
- break;
1306
- case 'val':
1307
- if (cur.val === nodeProperty) {
1308
- result.push(cur);
1309
- return onlyOne;
1310
- }
1311
- break;
1312
- default:
1313
- if (cur.key === nodeProperty) {
1314
- result.push(cur);
1315
- return onlyOne;
1316
- }
1317
- break;
1318
- }
1319
- }
1320
-
1321
- /**
1322
- * The function `_accumulatedByPropertyName` accumulates values from a given node based on the specified property name.
1323
- * @param {N} node - The `node` parameter is of type `N`, which represents a node in a data structure.
1324
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that
1325
- * can be either a string representing a property name or a reference to a `Node` object. If it is a string, it
1326
- * specifies the property name to be used for accumulating values. If it is a `Node` object, it specifies
1327
- */
1328
- protected _accumulatedByPropertyName(node: N, nodeOrPropertyName: NodeOrPropertyName = 'key') {
1329
- switch (nodeOrPropertyName) {
1330
- case 'key':
1331
- this.visitedKey.push(node.key);
1332
- break;
1333
- case 'val':
1334
- this.visitedVal.push(node.val);
1335
- break;
1336
- case 'node':
1337
- this.visitedNode.push(node);
1338
- break;
1339
- default:
1340
- this.visitedKey.push(node.key);
1341
- break;
1342
- }
1343
- }
1344
-
1345
- /**
1346
- * The time complexity of Morris traversal is O(n), it may slower than others
1347
- * The space complexity Morris traversal is O(1) because no using stack
1348
- */
1349
-
1350
- /**
1351
- * The function `_getResultByPropertyName` returns the corresponding property value based on the given node or property
1352
- * name.
1353
- * @param {NodeOrPropertyName} [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is an optional parameter that
1354
- * can accept either a `NodeOrPropertyName` type or be undefined.
1355
- * @returns The method `_getResultByPropertyName` returns an instance of `BinaryTreeNodeProperties<N>`.
1356
- */
1357
- protected _getResultByPropertyName(nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties<N> {
1358
- switch (nodeOrPropertyName) {
1359
- case 'key':
1360
- return this.visitedKey;
1361
- case 'val':
1362
- return this.visitedVal;
1363
- case 'node':
1364
- return this.visitedNode;
1365
- default:
1366
- return this.visitedKey;
1367
- }
1368
- }
1369
-
1370
1020
  // --- end additional methods ---
1371
1021
  }