data-structure-typed 1.37.1 → 1.37.3

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 (48) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/dist/data-structures/binary-tree/avl-tree.d.ts +5 -7
  3. package/dist/data-structures/binary-tree/avl-tree.js +7 -9
  4. package/dist/data-structures/binary-tree/avl-tree.js.map +1 -1
  5. package/dist/data-structures/binary-tree/binary-tree.d.ts +61 -209
  6. package/dist/data-structures/binary-tree/binary-tree.js +133 -269
  7. package/dist/data-structures/binary-tree/binary-tree.js.map +1 -1
  8. package/dist/data-structures/binary-tree/bst.d.ts +22 -19
  9. package/dist/data-structures/binary-tree/bst.js +68 -54
  10. package/dist/data-structures/binary-tree/bst.js.map +1 -1
  11. package/dist/data-structures/binary-tree/tree-multiset.d.ts +2 -36
  12. package/dist/data-structures/binary-tree/tree-multiset.js +3 -81
  13. package/dist/data-structures/binary-tree/tree-multiset.js.map +1 -1
  14. package/dist/data-structures/heap/heap.d.ts +1 -1
  15. package/dist/data-structures/heap/heap.js +1 -1
  16. package/dist/types/data-structures/binary-tree.d.ts +4 -2
  17. package/dist/types/data-structures/binary-tree.js +6 -6
  18. package/dist/types/data-structures/binary-tree.js.map +1 -1
  19. package/dist/types/data-structures/index.d.ts +2 -0
  20. package/lib/data-structures/binary-tree/avl-tree.d.ts +5 -7
  21. package/lib/data-structures/binary-tree/avl-tree.js +7 -9
  22. package/lib/data-structures/binary-tree/binary-tree.d.ts +61 -209
  23. package/lib/data-structures/binary-tree/binary-tree.js +134 -270
  24. package/lib/data-structures/binary-tree/bst.d.ts +22 -19
  25. package/lib/data-structures/binary-tree/bst.js +69 -55
  26. package/lib/data-structures/binary-tree/tree-multiset.d.ts +2 -36
  27. package/lib/data-structures/binary-tree/tree-multiset.js +4 -82
  28. package/lib/data-structures/heap/heap.d.ts +1 -1
  29. package/lib/data-structures/heap/heap.js +1 -1
  30. package/lib/types/data-structures/binary-tree.d.ts +4 -2
  31. package/lib/types/data-structures/binary-tree.js +5 -5
  32. package/lib/types/data-structures/index.d.ts +2 -0
  33. package/package.json +6 -6
  34. package/src/data-structures/binary-tree/avl-tree.ts +7 -9
  35. package/src/data-structures/binary-tree/binary-tree.ts +79 -54
  36. package/src/data-structures/binary-tree/bst.ts +37 -32
  37. package/src/data-structures/binary-tree/tree-multiset.ts +3 -3
  38. package/src/types/data-structures/binary-tree.ts +2 -2
  39. package/test/config.ts +1 -0
  40. package/test/integration/avl-tree.test.ts +23 -21
  41. package/test/integration/bst.test.ts +49 -44
  42. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +50 -0
  43. package/test/unit/data-structures/binary-tree/bst.test.ts +8 -1
  44. package/test/unit/data-structures/binary-tree/tree-multiset.test.ts +2 -1
  45. package/test/unit/data-structures/linked-list/linked-list.test.ts +1 -1
  46. package/test/utils/big-o.ts +2 -1
  47. package/umd/bundle.min.js +1 -1
  48. package/umd/bundle.min.js.map +1 -1
@@ -72,27 +72,25 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
72
72
 
73
73
  /**
74
74
  * The function overrides the add method of a binary tree node and balances the tree after inserting a new node.
75
- * @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier of the binary tree node that we want to add.
75
+ * @param keyOrNode - The `keyOrNode` parameter is either a key or a node that needs to be added to the binary tree.
76
76
  * @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It is of type
77
77
  * `N['val']`, which means it should be of the same type as the `val` property of the nodes in the binary tree.
78
78
  * @returns The method is returning the inserted node, or null or undefined if the insertion was not successful.
79
79
  */
80
- override add(key: BinaryTreeNodeKey, val?: N['val']): N | null | undefined {
80
+ override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
81
81
  // TODO support node as a param
82
- const inserted = super.add(key, val);
82
+ const inserted = super.add(keyOrNode, val);
83
83
  if (inserted) this._balancePath(inserted);
84
84
  return inserted;
85
85
  }
86
86
 
87
87
  /**
88
- * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after
89
- * deletion.
90
- * @param {BinaryTreeNodeKey} key - The `key` parameter represents the identifier of the binary tree node that needs to be
91
- * removed.
88
+ * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after deletion.
92
89
  * @returns The method is returning an array of `BinaryTreeDeletedResult<N>` objects.
90
+ * @param nodeOrKey - The `nodeOrKey` parameter is either a node or a key that needs to be deleted from the binary tree.
93
91
  */
94
- override delete(key: BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[] {
95
- const deletedResults = super.delete(key);
92
+ override delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[] {
93
+ const deletedResults = super.delete(nodeOrKey);
96
94
  for (const {needBalanced} of deletedResults) {
97
95
  if (needBalanced) {
98
96
  this._balancePath(needBalanced);
@@ -15,12 +15,7 @@ import type {
15
15
  MapCallback,
16
16
  MapCallbackReturn
17
17
  } from '../../types';
18
- import {
19
- BinaryTreeDeletedResult,
20
- DFSOrderPattern,
21
- FamilyPosition,
22
- LoopType
23
- } from '../../types';
18
+ import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
24
19
  import {IBinaryTree} from '../../interfaces';
25
20
  import {trampoline} from '../../utils';
26
21
  import {Queue} from '../queue';
@@ -111,8 +106,8 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
111
106
  */
112
107
  constructor(options?: BinaryTreeOptions) {
113
108
  if (options !== undefined) {
114
- const {loopType = LoopType.ITERATIVE} = options;
115
- this._loopType = loopType;
109
+ const {iterationType = IterationType.ITERATIVE} = options;
110
+ this._loopType = iterationType;
116
111
  }
117
112
  }
118
113
 
@@ -141,13 +136,13 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
141
136
  return this._size;
142
137
  }
143
138
 
144
- private _loopType: LoopType = LoopType.ITERATIVE;
139
+ private _loopType: IterationType = IterationType.ITERATIVE;
145
140
 
146
- get loopType(): LoopType {
141
+ get iterationType(): IterationType {
147
142
  return this._loopType;
148
143
  }
149
144
 
150
- set loopType(v: LoopType) {
145
+ set iterationType(v: IterationType) {
151
146
  this._loopType = v;
152
147
  }
153
148
 
@@ -372,13 +367,14 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
372
367
  * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
373
368
  * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
374
369
  * node), or `null`.
370
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of
375
371
  * @returns the height of the binary tree.
376
372
  */
377
- getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root): number {
373
+ getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): number {
378
374
  if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
379
375
  if (!beginRoot) return -1;
380
376
 
381
- if (this._loopType === LoopType.RECURSIVE) {
377
+ if (iterationType === IterationType.RECURSIVE) {
382
378
  const _getMaxHeight = (cur: N | null | undefined): number => {
383
379
  if (!cur) return -1;
384
380
  const leftHeight = _getMaxHeight(cur.left);
@@ -421,12 +417,13 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
421
417
  * @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It
422
418
  * represents the starting node from which to calculate the minimum height of a binary tree. If no value is provided
423
419
  * for `beginRoot`, the `this.root` property is used as the default value.
420
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
424
421
  * @returns The function `getMinHeight` returns the minimum height of the binary tree.
425
422
  */
426
- getMinHeight(beginRoot: N | null = this.root): number {
423
+ getMinHeight(beginRoot: N | null = this.root, iterationType = this.iterationType): number {
427
424
  if (!beginRoot) return -1;
428
425
 
429
- if (this._loopType === LoopType.RECURSIVE) {
426
+ if (iterationType === IterationType.RECURSIVE) {
430
427
  const _getMinHeight = (cur: N | null | undefined): number => {
431
428
  if (!cur) return 0;
432
429
  if (!cur.left && !cur.right) return 0;
@@ -486,19 +483,21 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
486
483
  * return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the
487
484
  * function will stop traversing the tree and return the first matching node. If `only
488
485
  * @param beginRoot
486
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
489
487
  * @returns an array of nodes (type N).
490
488
  */
491
489
  getNodes(
492
490
  nodeProperty: BinaryTreeNodeKey | N,
493
491
  callback: MapCallback<N> = this._defaultCallbackByKey,
494
492
  onlyOne = false,
495
- beginRoot: N | null = this.root
493
+ beginRoot: N | null = this.root,
494
+ iterationType = this.iterationType
496
495
  ): N[] {
497
496
  if (!beginRoot) return [];
498
497
 
499
498
  const ans: N[] = [];
500
499
 
501
- if (this.loopType === LoopType.RECURSIVE) {
500
+ if (iterationType === IterationType.RECURSIVE) {
502
501
  const _traverse = (cur: N) => {
503
502
  if (callback(cur) === nodeProperty) {
504
503
  ans.push(cur);
@@ -534,11 +533,18 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
534
533
  * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`.
535
534
  * It represents the property of the binary tree node that you want to check.
536
535
  * specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'.
536
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty.
537
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
537
538
  * @returns a boolean value.
538
539
  */
539
- has(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback<N> = this._defaultCallbackByKey): boolean {
540
+ has(
541
+ nodeProperty: BinaryTreeNodeKey | N,
542
+ callback: MapCallback<N> = this._defaultCallbackByKey,
543
+ beginRoot = this.root,
544
+ iterationType = this.iterationType
545
+ ): boolean {
540
546
  // TODO may support finding node by value equal
541
- return this.getNodes(nodeProperty, callback, true).length > 0;
547
+ return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType).length > 0;
542
548
  }
543
549
 
544
550
  /**
@@ -549,12 +555,19 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
549
555
  * It represents the property of the binary tree node that you want to search for.
550
556
  * specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the
551
557
  * default value is set to `'key'`.
558
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty.
559
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree.
552
560
  * @returns either the value of the specified property of the node, or the node itself if no property name is provided.
553
561
  * If no matching node is found, it returns null.
554
562
  */
555
- get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback<N> = this._defaultCallbackByKey): N | null {
563
+ get(
564
+ nodeProperty: BinaryTreeNodeKey | N,
565
+ callback: MapCallback<N> = this._defaultCallbackByKey,
566
+ beginRoot = this.root,
567
+ iterationType = this.iterationType
568
+ ): N | null {
556
569
  // TODO may support finding node by value equal
557
- return this.getNodes(nodeProperty, callback, true)[0] ?? null;
570
+ return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null;
558
571
  }
559
572
 
560
573
  /**
@@ -586,17 +599,18 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
586
599
  * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a
587
600
  * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree
588
601
  * node), or `null`.
602
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree.
589
603
  * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is
590
604
  * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal
591
605
  * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost
592
606
  * node is found (
593
607
  */
594
- getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root): N | null {
608
+ getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): N | null {
595
609
  if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
596
610
 
597
611
  if (!beginRoot) return beginRoot;
598
612
 
599
- if (this._loopType === LoopType.RECURSIVE) {
613
+ if (iterationType === IterationType.RECURSIVE) {
600
614
  const _traverse = (cur: N): N => {
601
615
  if (!cur.left) return cur;
602
616
  return _traverse(cur.left);
@@ -620,15 +634,16 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
620
634
  * @param {N | null} [beginRoot] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the
621
635
  * starting node from which we want to find the rightmost node. If no node is provided, the function will default to
622
636
  * using the root node of the data structure.
637
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
623
638
  * @returns The `getRightMost` function returns the rightmost node in a binary tree. If the `node` parameter is provided,
624
639
  * it returns the rightmost node starting from that node. If the `node` parameter is not provided, it returns the
625
640
  * rightmost node starting from the root of the binary tree.
626
641
  */
627
- getRightMost(beginRoot: N | null = this.root): N | null {
642
+ getRightMost(beginRoot: N | null = this.root, iterationType = this.iterationType): N | null {
628
643
  // TODO support get right most by passing key in
629
644
  if (!beginRoot) return beginRoot;
630
645
 
631
- if (this._loopType === LoopType.RECURSIVE) {
646
+ if (iterationType === IterationType.RECURSIVE) {
632
647
  const _traverse = (cur: N): N => {
633
648
  if (!cur.right) return cur;
634
649
  return _traverse(cur.right);
@@ -648,25 +663,26 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
648
663
 
649
664
  /**
650
665
  * The function checks if a binary search tree is valid by traversing it either recursively or iteratively.
651
- * @param {N | null} subTreeRoot - The `node` parameter represents the root node of a binary search tree (BST).
666
+ * @param {N | null} beginRoot - The `node` parameter represents the root node of a binary search tree (BST).
667
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
652
668
  * @returns a boolean value.
653
669
  */
654
- isSubtreeBST(subTreeRoot: N | null): boolean {
670
+ isSubtreeBST(beginRoot: N, iterationType = this.iterationType): boolean {
655
671
  // TODO there is a bug
656
- if (!subTreeRoot) return true;
672
+ if (!beginRoot) return true;
657
673
 
658
- if (this._loopType === LoopType.RECURSIVE) {
674
+ if (iterationType === IterationType.RECURSIVE) {
659
675
  const dfs = (cur: N | null | undefined, min: BinaryTreeNodeKey, max: BinaryTreeNodeKey): boolean => {
660
676
  if (!cur) return true;
661
677
  if (cur.key <= min || cur.key >= max) return false;
662
678
  return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max);
663
679
  };
664
680
 
665
- return dfs(subTreeRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
681
+ return dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
666
682
  } else {
667
683
  const stack = [];
668
684
  let prev = Number.MIN_SAFE_INTEGER,
669
- curr: N | null | undefined = subTreeRoot;
685
+ curr: N | null | undefined = beginRoot;
670
686
  while (curr || stack.length > 0) {
671
687
  while (curr) {
672
688
  stack.push(curr);
@@ -685,37 +701,40 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
685
701
  * The function isBST checks if the binary tree is valid binary search tree.
686
702
  * @returns The `isBST()` function is returning a boolean value.
687
703
  */
688
- isBST(): boolean {
689
- return this.isSubtreeBST(this.root);
704
+ isBST(iterationType = this.iterationType): boolean {
705
+ if (this.root === null) return true;
706
+ return this.isSubtreeBST(this.root, iterationType);
690
707
  }
691
708
 
692
709
  /**
693
710
  * The function `subTreeTraverse` adds a delta value to a specified property of each node in a subtree.
694
- * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary
711
+ * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the root node of a binary
695
712
  * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to.
696
713
  * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
697
714
  * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'.
715
+ * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop
698
716
  * @returns a boolean value.
699
717
  */
700
718
  subTreeTraverse(
701
719
  callback: MapCallback<N> = this._defaultCallbackByKey,
702
- subTreeRoot: N | BinaryTreeNodeKey | null = this.root
720
+ beginRoot: N | BinaryTreeNodeKey | null = this.root,
721
+ iterationType = this.iterationType
703
722
  ): MapCallbackReturn<N>[] {
704
- if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot);
723
+ if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
705
724
 
706
725
  const ans: MapCallbackReturn<N>[] = [];
707
- if (!subTreeRoot) return ans;
726
+ if (!beginRoot) return ans;
708
727
 
709
- if (this._loopType === LoopType.RECURSIVE) {
728
+ if (iterationType === IterationType.RECURSIVE) {
710
729
  const _traverse = (cur: N) => {
711
730
  ans.push(callback(cur));
712
731
  cur.left && _traverse(cur.left);
713
732
  cur.right && _traverse(cur.right);
714
733
  };
715
734
 
716
- _traverse(subTreeRoot);
735
+ _traverse(beginRoot);
717
736
  } else {
718
- const stack: N[] = [subTreeRoot];
737
+ const stack: N[] = [beginRoot];
719
738
 
720
739
  while (stack.length > 0) {
721
740
  const cur = stack.pop()!;
@@ -734,18 +753,18 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
734
753
  * @param callback
735
754
  * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the
736
755
  * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
737
- * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`.
756
+ * @param iterationType - The type of loop to use for the depth-first search traversal. The default value is `IterationType.ITERATIVE`.
738
757
  * @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.
739
758
  */
740
759
  dfs(
741
760
  callback: MapCallback<N> = this._defaultCallbackByKey,
742
761
  pattern: DFSOrderPattern = 'in',
743
762
  beginRoot: N | null = this.root,
744
- loopType: LoopType = LoopType.ITERATIVE
763
+ iterationType: IterationType = IterationType.ITERATIVE
745
764
  ): MapCallbackReturn<N>[] {
746
765
  if (!beginRoot) return [];
747
766
  const ans: MapCallbackReturn<N>[] = [];
748
- if (loopType === LoopType.RECURSIVE) {
767
+ if (iterationType === IterationType.RECURSIVE) {
749
768
  const _traverse = (node: N) => {
750
769
  switch (pattern) {
751
770
  case 'in':
@@ -812,30 +831,31 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
812
831
 
813
832
  /**
814
833
  * The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels.
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.
816
834
  * @param callback - The `callback` parameter is a function that takes a node and a level as parameters and returns a value.
817
835
  * @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.
836
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty.
837
+ * @param iterationType
818
838
  */
819
839
  bfs(
820
840
  callback: BFSCallback<N> = this._defaultCallbackByKey,
821
841
  withLevel: boolean = false,
822
- node?: N | null
842
+ beginRoot: N | null = this.root,
843
+ iterationType = this.iterationType
823
844
  ): BFSCallbackReturn<N>[] {
824
- if (!node) node = this.root;
825
- if (!node) return [];
845
+ if (!beginRoot) return [];
826
846
 
827
847
  const ans: BFSCallbackReturn<N>[] = [];
828
848
 
829
- if (this.loopType === LoopType.RECURSIVE) {
849
+ if (iterationType === IterationType.RECURSIVE) {
830
850
  const _recursive = (node: N, level: number) => {
831
851
  callback && ans.push(callback(node, withLevel ? level : undefined));
832
852
  if (node.left) _recursive(node.left, level + 1);
833
853
  if (node.right) _recursive(node.right, level + 1);
834
854
  };
835
855
 
836
- _recursive(node, 0);
856
+ _recursive(beginRoot, 0);
837
857
  } else {
838
- const stack: [N, number][] = [[node, 0]];
858
+ const stack: [N, number][] = [[beginRoot, 0]];
839
859
 
840
860
  while (stack.length > 0) {
841
861
  const head = stack.pop()!;
@@ -875,18 +895,23 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
875
895
 
876
896
  /**
877
897
  * The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm.
898
+ * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete,
899
+ * the tree's structure should be restored to its original state to maintain the tree's integrity.
900
+ * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape.
878
901
  * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order).
879
902
  * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
903
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the
880
904
  * @returns An array of BinaryTreeNodeProperties<N> objects.
881
905
  */
882
906
  morris(
883
907
  callback: MapCallback<N> = this._defaultCallbackByKey,
884
- pattern: DFSOrderPattern = 'in'
908
+ pattern: DFSOrderPattern = 'in',
909
+ beginRoot: N | null = this.root
885
910
  ): MapCallbackReturn<N>[] {
886
- if (this.root === null) return [];
911
+ if (beginRoot === null) return [];
887
912
  const ans: MapCallbackReturn<N>[] = [];
888
913
 
889
- let cur: N | null | undefined = this.root;
914
+ let cur: N | null | undefined = beginRoot;
890
915
  const _reverseEdge = (node: N | null | undefined) => {
891
916
  let pre: N | null | undefined = null;
892
917
  let next: N | null | undefined = null;
@@ -957,7 +982,7 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
957
982
  }
958
983
  cur = cur.right;
959
984
  }
960
- _printEdge(this.root);
985
+ _printEdge(beginRoot);
961
986
  break;
962
987
  }
963
988
  return ans;
@@ -13,7 +13,7 @@ import type {
13
13
  MapCallback,
14
14
  MapCallbackReturn
15
15
  } from '../../types';
16
- import {CP, LoopType} from '../../types';
16
+ import {CP, IterationType} from '../../types';
17
17
  import {BinaryTree, BinaryTreeNode} from './binary-tree';
18
18
  import {IBinaryTree} from '../../interfaces';
19
19
  import {Queue} from '../queue';
@@ -134,12 +134,14 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
134
134
  * to the binary search tree.
135
135
  * @param {N['val'][]} data - The values of tree nodes
136
136
  * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method.
137
+ * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a
137
138
  * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
138
139
  */
139
140
  override addMany(
140
141
  keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
141
142
  data?: N['val'][],
142
- isBalanceAdd = true
143
+ isBalanceAdd = true,
144
+ iterationType = this.iterationType
143
145
  ): (N | null | undefined)[] {
144
146
  // TODO this addMany function is inefficient, it should be optimized
145
147
  function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] {
@@ -199,7 +201,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
199
201
  }
200
202
  }
201
203
  };
202
- if (this.loopType === LoopType.RECURSIVE) {
204
+ if (iterationType === IterationType.RECURSIVE) {
203
205
  recursive(sortedKeysOrNodes, sortedData);
204
206
  } else {
205
207
  iterative();
@@ -221,16 +223,15 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
221
223
  }
222
224
 
223
225
  /**
224
- * The function returns the key of the rightmost node if the comparison between two values is less than, the key of the
225
- * leftmost node if the comparison is greater than, and the key of the rightmost node otherwise.
226
- * @returns The method `lastKey()` returns the key of the rightmost node in the binary tree if the comparison between
227
- * the values at index 0 and 1 is less than, otherwise it returns the key of the leftmost node. If the comparison is
228
- * equal, it returns the key of the rightmost node. If there are no nodes in the tree, it returns 0.
226
+ * lastKey returns the last key in a binary tree. If the binary tree is empty, it returns 0.
227
+ * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to begin
228
+ * the search for the last key.
229
+ * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a recursive or iterative approach to search for the last key.
229
230
  */
230
- lastKey(): BinaryTreeNodeKey {
231
- if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.key ?? 0;
232
- else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.key ?? 0;
233
- else return this.getRightMost()?.key ?? 0;
231
+ lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BinaryTreeNodeKey {
232
+ if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
233
+ else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0;
234
+ else return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
234
235
  }
235
236
 
236
237
  /**
@@ -243,18 +244,20 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
243
244
  * return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne`
244
245
  * is set to `true`, the function will return an array with only one node (if
245
246
  * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to
247
+ * @param iterationType
246
248
  * @returns an array of nodes (type N).
247
249
  */
248
250
  override getNodes(
249
251
  nodeProperty: BinaryTreeNodeKey | N,
250
252
  callback: MapCallback<N> = this._defaultCallbackByKey,
251
253
  onlyOne = false,
252
- beginRoot: N | null = this.root
254
+ beginRoot: N | null = this.root,
255
+ iterationType = this.iterationType
253
256
  ): N[] {
254
257
  if (!beginRoot) return [];
255
258
  const ans: N[] = [];
256
259
 
257
- if (this.loopType === LoopType.RECURSIVE) {
260
+ if (iterationType === IterationType.RECURSIVE) {
258
261
  const _traverse = (cur: N) => {
259
262
  const callbackResult = callback(cur);
260
263
  if (callbackResult === nodeProperty) {
@@ -305,43 +308,45 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
305
308
  * The `lesserOrGreaterTraverse` function adds a delta value to the specified property of all nodes in a binary tree that
306
309
  * have a greater value than a given node.
307
310
  * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value.
308
- * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), `BinaryTreeNodeKey`, or `null`. It
309
311
  * represents the node in the binary tree to which the delta value will be added.
310
312
  * @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta
313
+ * @param targetNode - The `targetNode` parameter is an optional parameter that specifies the node in the binary tree
314
+ * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a
311
315
  */
312
316
  lesserOrGreaterTraverse(
313
317
  callback: MapCallback<N> = this._defaultCallbackByKey,
314
318
  lesserOrGreater: CP = CP.lt,
315
- node: N | BinaryTreeNodeKey | null
319
+ targetNode: N | BinaryTreeNodeKey | null = this.root,
320
+ iterationType = this.iterationType
316
321
  ): MapCallbackReturn<N> {
317
- if (typeof node === 'number') node = this.get(node);
322
+ if (typeof targetNode === 'number') targetNode = this.get(targetNode);
318
323
  const ans: MapCallbackReturn<N>[] = [];
319
- if (!node) return [];
320
- const key = node.key;
321
- if (!this.root) return false;
324
+ if (!targetNode) return ans;
325
+ const targetKey = targetNode.key;
326
+ if (!this.root) return ans;
322
327
 
323
- if (this.loopType === LoopType.RECURSIVE) {
328
+ if (iterationType === IterationType.RECURSIVE) {
324
329
  const _traverse = (cur: N) => {
325
- const compared = this._compare(cur.key, key);
330
+ const compared = this._compare(cur.key, targetKey);
326
331
  if (compared === lesserOrGreater) ans.push(callback(cur));
327
332
 
328
333
  if (!cur.left && !cur.right) return;
329
- if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) _traverse(cur.left);
330
- if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) _traverse(cur.right);
334
+ if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) _traverse(cur.left);
335
+ if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) _traverse(cur.right);
331
336
  };
332
337
 
333
338
  _traverse(this.root);
334
- return true;
339
+ return ans;
335
340
  } else {
336
341
  const queue = new Queue<N>([this.root]);
337
342
  while (queue.size > 0) {
338
343
  const cur = queue.shift();
339
344
  if (cur) {
340
- const compared = this._compare(cur.key, key);
345
+ const compared = this._compare(cur.key, targetKey);
341
346
  if (compared === lesserOrGreater) ans.push(callback(cur));
342
347
 
343
- if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) queue.push(cur.left);
344
- if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) queue.push(cur.right);
348
+ if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) queue.push(cur.left);
349
+ if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) queue.push(cur.right);
345
350
  }
346
351
  }
347
352
  return ans;
@@ -363,13 +368,13 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
363
368
  * constructs a balanced binary search tree using either a recursive or iterative approach.
364
369
  * @returns The function `perfectlyBalance()` returns a boolean value.
365
370
  */
366
- perfectlyBalance(): boolean {
371
+ perfectlyBalance(iterationType = this.iterationType): boolean {
367
372
  const sorted = this.dfs(node => node, 'in'),
368
373
  n = sorted.length;
369
374
  this.clear();
370
375
 
371
376
  if (sorted.length < 1) return false;
372
- if (this.loopType === LoopType.RECURSIVE) {
377
+ if (iterationType === IterationType.RECURSIVE) {
373
378
  const buildBalanceBST = (l: number, r: number) => {
374
379
  if (l > r) return;
375
380
  const m = l + Math.floor((r - l) / 2);
@@ -404,12 +409,12 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
404
409
  * The function `isAVLBalanced` checks if a binary tree is balanced according to the AVL tree property.
405
410
  * @returns a boolean value.
406
411
  */
407
- isAVLBalanced(): boolean {
412
+ isAVLBalanced(iterationType = this.iterationType): boolean {
408
413
  if (!this.root) return true;
409
414
 
410
415
  let balanced = true;
411
416
 
412
- if (this.loopType === LoopType.RECURSIVE) {
417
+ if (iterationType === IterationType.RECURSIVE) {
413
418
  const _height = (cur: N | null | undefined): number => {
414
419
  if (!cur) return 0;
415
420
  const leftHeight = _height(cur.left),
@@ -6,7 +6,7 @@
6
6
  * @license MIT License
7
7
  */
8
8
  import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
9
- import {BinaryTreeDeletedResult, CP, FamilyPosition, LoopType} from '../../types';
9
+ import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType} from '../../types';
10
10
  import {IBinaryTree} from '../../interfaces';
11
11
  import {AVLTree, AVLTreeNode} from './avl-tree';
12
12
 
@@ -246,14 +246,14 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
246
246
  * constructs a balanced binary search tree using either a recursive or iterative approach.
247
247
  * @returns The function `perfectlyBalance()` returns a boolean value.
248
248
  */
249
- override perfectlyBalance(): boolean {
249
+ override perfectlyBalance(iterationType = this.iterationType): boolean {
250
250
  const sorted = this.dfs(node => node, 'in'),
251
251
  n = sorted.length;
252
252
  if (sorted.length < 1) return false;
253
253
 
254
254
  this.clear();
255
255
 
256
- if (this.loopType === LoopType.RECURSIVE) {
256
+ if (iterationType === IterationType.RECURSIVE) {
257
257
  const buildBalanceBST = (l: number, r: number) => {
258
258
  if (l > r) return;
259
259
  const m = l + Math.floor((r - l) / 2);
@@ -7,7 +7,7 @@ import {BinaryTreeNode} from '../../data-structures/binary-tree';
7
7
  * - `recursive`: Indicates the recursive loop type (with loops that call themselves).
8
8
  */
9
9
 
10
- export enum LoopType {
10
+ export enum IterationType {
11
11
  ITERATIVE = 'ITERATIVE',
12
12
  RECURSIVE = 'RECURSIVE'
13
13
  }
@@ -44,4 +44,4 @@ export type BinaryTreeNodeProperties<N extends BinaryTreeNode<N['val'], N>> =
44
44
 
45
45
  export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
46
46
 
47
- export type BinaryTreeOptions = { loopType?: LoopType }
47
+ export type BinaryTreeOptions = { iterationType?: IterationType }
package/test/config.ts ADDED
@@ -0,0 +1 @@
1
+ export const isDebugTest = true;