min-heap-typed 1.41.8 → 1.42.0

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.
@@ -238,67 +238,18 @@ export declare class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = Binary
238
238
  * @returns a boolean value.
239
239
  */
240
240
  isBST(iterationType?: IterationType): boolean;
241
- /**
242
- * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
243
- * node, either recursively or iteratively.
244
- * @param callback - The `callback` parameter is a function that will be called on each node in the
245
- * subtree traversal. It takes a single argument, which is the current node being traversed, and
246
- * returns a value. The return values from each callback invocation will be collected and returned as
247
- * an array.
248
- * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point
249
- * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to
250
- * start from the root of the tree.
251
- * @param iterationType - The `iterationType` parameter determines the type of traversal to be
252
- * performed on the binary tree. It can have two possible values:
253
- * @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
254
- */
255
- subTreeTraverse<C extends BTNCallback<N>>(callback?: C, beginRoot?: BTNKey | N | null, iterationType?: IterationType): ReturnType<C>[];
256
- /**
257
- * The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback
258
- * function on each node according to a specified order pattern.
259
- * @param callback - The `callback` parameter is a function that will be called on each node during
260
- * the depth-first search traversal. It takes a node as input and returns a value. The default value
261
- * is `this.defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
262
- * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
263
- * nodes are visited during the depth-first search. There are three possible values for `pattern`:
264
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
265
- * search. It determines where the search will begin in the tree or graph structure. If `beginRoot`
266
- * is `null`, an empty array will be returned.
267
- * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
268
- * iteration used in the depth-first search algorithm. It can have two possible values:
269
- * @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
270
- */
271
- dfs<C extends BTNCallback<N>>(callback?: C, pattern?: DFSOrderPattern, beginRoot?: N | null, iterationType?: IterationType): ReturnType<C>[];
272
- /**
273
- * The bfs function performs a breadth-first search traversal on a binary tree, executing a callback
274
- * function on each node.
275
- * @param callback - The `callback` parameter is a function that will be called for each node in the
276
- * breadth-first search. It takes a node of type `N` as its argument and returns a value of type
277
- * `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this.defaultOneParamCallback
278
- * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
279
- * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
280
- * will not be performed and an empty array will be returned.
281
- * @param iterationType - The `iterationType` parameter determines the type of iteration to be used
282
- * in the breadth-first search (BFS) algorithm. It can have two possible values:
283
- * @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
284
- */
285
- bfs<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType): ReturnType<C>[];
286
- /**
287
- * The `listLevels` function takes a binary tree node and a callback function, and returns an array
288
- * of arrays representing the levels of the tree.
289
- * @param {C} callback - The `callback` parameter is a function that will be called on each node in
290
- * the tree. It takes a node as input and returns a value. The return type of the callback function
291
- * is determined by the generic type `C`.
292
- * @param {N | null} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree
293
- * traversal. It can be any node in the binary tree. If no node is provided, the traversal will start
294
- * from the root node of the binary tree.
295
- * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done
296
- * recursively or iteratively. It can have two possible values:
297
- * @returns The function `listLevels` returns an array of arrays, where each inner array represents a
298
- * level in a binary tree. Each inner array contains the return type of the provided callback
299
- * function `C` applied to the nodes at that level.
300
- */
301
- listLevels<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType): ReturnType<C>[][];
241
+ subTreeTraverse<C extends BTNCallback<N>>(callback?: C, beginRoot?: BTNKey | N | null, iterationType?: IterationType, includeNull?: false): ReturnType<C>[];
242
+ subTreeTraverse<C extends BTNCallback<N>>(callback?: C, beginRoot?: BTNKey | N | null, iterationType?: IterationType, includeNull?: undefined): ReturnType<C>[];
243
+ subTreeTraverse<C extends BTNCallback<N | null>>(callback?: C, beginRoot?: BTNKey | N | null, iterationType?: IterationType, includeNull?: true): ReturnType<C>[];
244
+ dfs<C extends BTNCallback<N>>(callback?: C, pattern?: DFSOrderPattern, beginRoot?: N | null, iterationType?: IterationType, includeNull?: false): ReturnType<C>[];
245
+ dfs<C extends BTNCallback<N>>(callback?: C, pattern?: DFSOrderPattern, beginRoot?: N | null, iterationType?: IterationType, includeNull?: undefined): ReturnType<C>[];
246
+ dfs<C extends BTNCallback<N | null>>(callback?: C, pattern?: DFSOrderPattern, beginRoot?: N | null, iterationType?: IterationType, includeNull?: true): ReturnType<C>[];
247
+ bfs<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: false): ReturnType<C>[];
248
+ bfs<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: undefined): ReturnType<C>[];
249
+ bfs<C extends BTNCallback<N | null>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: true): ReturnType<C>[];
250
+ listLevels<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: false): ReturnType<C>[][];
251
+ listLevels<C extends BTNCallback<N>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: undefined): ReturnType<C>[][];
252
+ listLevels<C extends BTNCallback<N | null>>(callback?: C, beginRoot?: N | null, iterationType?: IterationType, includeNull?: true): ReturnType<C>[][];
302
253
  /**
303
254
  * The function returns the predecessor node of a given node in a binary tree.
304
255
  * @param {N} node - The parameter "node" represents a node in a binary tree.
@@ -703,9 +703,10 @@ class BinaryTree {
703
703
  * start from the root of the tree.
704
704
  * @param iterationType - The `iterationType` parameter determines the type of traversal to be
705
705
  * performed on the binary tree. It can have two possible values:
706
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
706
707
  * @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
707
708
  */
708
- subTreeTraverse(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
709
+ subTreeTraverse(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
709
710
  if (typeof beginRoot === 'number')
710
711
  beginRoot = this.getNode(beginRoot);
711
712
  const ans = [];
@@ -713,9 +714,17 @@ class BinaryTree {
713
714
  return ans;
714
715
  if (iterationType === types_1.IterationType.RECURSIVE) {
715
716
  const _traverse = (cur) => {
716
- ans.push(callback(cur));
717
- cur.left && _traverse(cur.left);
718
- cur.right && _traverse(cur.right);
717
+ if (cur !== undefined) {
718
+ ans.push(callback(cur));
719
+ if (includeNull) {
720
+ cur !== null && cur.left !== undefined && _traverse(cur.left);
721
+ cur !== null && cur.right !== undefined && _traverse(cur.right);
722
+ }
723
+ else {
724
+ cur !== null && cur.left && _traverse(cur.left);
725
+ cur !== null && cur.right && _traverse(cur.right);
726
+ }
727
+ }
719
728
  };
720
729
  _traverse(beginRoot);
721
730
  }
@@ -723,9 +732,17 @@ class BinaryTree {
723
732
  const stack = [beginRoot];
724
733
  while (stack.length > 0) {
725
734
  const cur = stack.pop();
726
- ans.push(callback(cur));
727
- cur.right && stack.push(cur.right);
728
- cur.left && stack.push(cur.left);
735
+ if (cur !== undefined) {
736
+ ans.push(callback(cur));
737
+ if (includeNull) {
738
+ cur !== null && cur.right !== undefined && stack.push(cur.right);
739
+ cur !== null && cur.left !== undefined && stack.push(cur.left);
740
+ }
741
+ else {
742
+ cur !== null && cur.right && stack.push(cur.right);
743
+ cur !== null && cur.left && stack.push(cur.left);
744
+ }
745
+ }
729
746
  }
730
747
  }
731
748
  return ans;
@@ -743,9 +760,10 @@ class BinaryTree {
743
760
  * is `null`, an empty array will be returned.
744
761
  * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
745
762
  * iteration used in the depth-first search algorithm. It can have two possible values:
763
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
746
764
  * @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
747
765
  */
748
- dfs(callback = this.defaultOneParamCallback, pattern = 'in', beginRoot = this.root, iterationType = types_1.IterationType.ITERATIVE) {
766
+ dfs(callback = this.defaultOneParamCallback, pattern = 'in', beginRoot = this.root, iterationType = types_1.IterationType.ITERATIVE, includeNull = false) {
749
767
  if (!beginRoot)
750
768
  return [];
751
769
  const ans = [];
@@ -753,25 +771,52 @@ class BinaryTree {
753
771
  const _traverse = (node) => {
754
772
  switch (pattern) {
755
773
  case 'in':
756
- if (node.left)
757
- _traverse(node.left);
758
- ans.push(callback(node));
759
- if (node.right)
760
- _traverse(node.right);
774
+ if (includeNull) {
775
+ if (node !== null && node.left !== undefined)
776
+ _traverse(node.left);
777
+ ans.push(callback(node));
778
+ if (node !== null && node.right !== undefined)
779
+ _traverse(node.right);
780
+ }
781
+ else {
782
+ if (node !== null && node.left)
783
+ _traverse(node.left);
784
+ ans.push(callback(node));
785
+ if (node !== null && node.right)
786
+ _traverse(node.right);
787
+ }
761
788
  break;
762
789
  case 'pre':
763
- ans.push(callback(node));
764
- if (node.left)
765
- _traverse(node.left);
766
- if (node.right)
767
- _traverse(node.right);
790
+ if (includeNull) {
791
+ ans.push(callback(node));
792
+ if (node !== null && node.left !== undefined)
793
+ _traverse(node.left);
794
+ if (node !== null && node.right !== undefined)
795
+ _traverse(node.right);
796
+ }
797
+ else {
798
+ ans.push(callback(node));
799
+ if (node !== null && node.left)
800
+ _traverse(node.left);
801
+ if (node !== null && node.right)
802
+ _traverse(node.right);
803
+ }
768
804
  break;
769
805
  case 'post':
770
- if (node.left)
771
- _traverse(node.left);
772
- if (node.right)
773
- _traverse(node.right);
774
- ans.push(callback(node));
806
+ if (includeNull) {
807
+ if (node !== null && node.left !== undefined)
808
+ _traverse(node.left);
809
+ if (node !== null && node.right !== undefined)
810
+ _traverse(node.right);
811
+ ans.push(callback(node));
812
+ }
813
+ else {
814
+ if (node !== null && node.left)
815
+ _traverse(node.left);
816
+ if (node !== null && node.right)
817
+ _traverse(node.right);
818
+ ans.push(callback(node));
819
+ }
775
820
  break;
776
821
  }
777
822
  };
@@ -782,32 +827,40 @@ class BinaryTree {
782
827
  const stack = [{ opt: 0, node: beginRoot }];
783
828
  while (stack.length > 0) {
784
829
  const cur = stack.pop();
785
- if (!cur || !cur.node)
830
+ if (cur === undefined)
786
831
  continue;
832
+ if (includeNull) {
833
+ if (cur.node === undefined)
834
+ continue;
835
+ }
836
+ else {
837
+ if (cur.node === null || cur.node === undefined)
838
+ continue;
839
+ }
787
840
  if (cur.opt === 1) {
788
841
  ans.push(callback(cur.node));
789
842
  }
790
843
  else {
791
844
  switch (pattern) {
792
845
  case 'in':
793
- stack.push({ opt: 0, node: cur.node.right });
846
+ cur.node && stack.push({ opt: 0, node: cur.node.right });
794
847
  stack.push({ opt: 1, node: cur.node });
795
- stack.push({ opt: 0, node: cur.node.left });
848
+ cur.node && stack.push({ opt: 0, node: cur.node.left });
796
849
  break;
797
850
  case 'pre':
798
- stack.push({ opt: 0, node: cur.node.right });
799
- stack.push({ opt: 0, node: cur.node.left });
851
+ cur.node && stack.push({ opt: 0, node: cur.node.right });
852
+ cur.node && stack.push({ opt: 0, node: cur.node.left });
800
853
  stack.push({ opt: 1, node: cur.node });
801
854
  break;
802
855
  case 'post':
803
856
  stack.push({ opt: 1, node: cur.node });
804
- stack.push({ opt: 0, node: cur.node.right });
805
- stack.push({ opt: 0, node: cur.node.left });
857
+ cur.node && stack.push({ opt: 0, node: cur.node.right });
858
+ cur.node && stack.push({ opt: 0, node: cur.node.left });
806
859
  break;
807
860
  default:
808
- stack.push({ opt: 0, node: cur.node.right });
861
+ cur.node && stack.push({ opt: 0, node: cur.node.right });
809
862
  stack.push({ opt: 1, node: cur.node });
810
- stack.push({ opt: 0, node: cur.node.left });
863
+ cur.node && stack.push({ opt: 0, node: cur.node.left });
811
864
  break;
812
865
  }
813
866
  }
@@ -826,9 +879,10 @@ class BinaryTree {
826
879
  * will not be performed and an empty array will be returned.
827
880
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be used
828
881
  * in the breadth-first search (BFS) algorithm. It can have two possible values:
882
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
829
883
  * @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
830
884
  */
831
- bfs(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
885
+ bfs(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
832
886
  if (!beginRoot)
833
887
  return [];
834
888
  const ans = [];
@@ -839,10 +893,18 @@ class BinaryTree {
839
893
  return;
840
894
  const current = queue.shift();
841
895
  ans.push(callback(current));
842
- if (current.left)
843
- queue.push(current.left);
844
- if (current.right)
845
- queue.push(current.right);
896
+ if (includeNull) {
897
+ if (current && current.left !== undefined)
898
+ queue.push(current.left);
899
+ if (current && current.right !== undefined)
900
+ queue.push(current.right);
901
+ }
902
+ else {
903
+ if (current.left)
904
+ queue.push(current.left);
905
+ if (current.right)
906
+ queue.push(current.right);
907
+ }
846
908
  traverse(level + 1);
847
909
  };
848
910
  traverse(0);
@@ -854,10 +916,18 @@ class BinaryTree {
854
916
  for (let i = 0; i < levelSize; i++) {
855
917
  const current = queue.shift();
856
918
  ans.push(callback(current));
857
- if (current.left)
858
- queue.push(current.left);
859
- if (current.right)
860
- queue.push(current.right);
919
+ if (includeNull) {
920
+ if (current !== null && current.left !== undefined)
921
+ queue.push(current.left);
922
+ if (current !== null && current.right !== undefined)
923
+ queue.push(current.right);
924
+ }
925
+ else {
926
+ if (current.left)
927
+ queue.push(current.left);
928
+ if (current.right)
929
+ queue.push(current.right);
930
+ }
861
931
  }
862
932
  }
863
933
  }
@@ -874,11 +944,12 @@ class BinaryTree {
874
944
  * from the root node of the binary tree.
875
945
  * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done
876
946
  * recursively or iteratively. It can have two possible values:
947
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
877
948
  * @returns The function `listLevels` returns an array of arrays, where each inner array represents a
878
949
  * level in a binary tree. Each inner array contains the return type of the provided callback
879
950
  * function `C` applied to the nodes at that level.
880
951
  */
881
- listLevels(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
952
+ listLevels(callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
882
953
  if (!beginRoot)
883
954
  return [];
884
955
  const levelsNodes = [];
@@ -887,10 +958,18 @@ class BinaryTree {
887
958
  if (!levelsNodes[level])
888
959
  levelsNodes[level] = [];
889
960
  levelsNodes[level].push(callback(node));
890
- if (node.left)
891
- _recursive(node.left, level + 1);
892
- if (node.right)
893
- _recursive(node.right, level + 1);
961
+ if (includeNull) {
962
+ if (node && node.left !== undefined)
963
+ _recursive(node.left, level + 1);
964
+ if (node && node.right !== undefined)
965
+ _recursive(node.right, level + 1);
966
+ }
967
+ else {
968
+ if (node && node.left)
969
+ _recursive(node.left, level + 1);
970
+ if (node && node.right)
971
+ _recursive(node.right, level + 1);
972
+ }
894
973
  };
895
974
  _recursive(beginRoot, 0);
896
975
  }
@@ -902,10 +981,18 @@ class BinaryTree {
902
981
  if (!levelsNodes[level])
903
982
  levelsNodes[level] = [];
904
983
  levelsNodes[level].push(callback(node));
905
- if (node.right)
906
- stack.push([node.right, level + 1]);
907
- if (node.left)
908
- stack.push([node.left, level + 1]);
984
+ if (includeNull) {
985
+ if (node && node.right !== undefined)
986
+ stack.push([node.right, level + 1]);
987
+ if (node && node.left !== undefined)
988
+ stack.push([node.left, level + 1]);
989
+ }
990
+ else {
991
+ if (node && node.right)
992
+ stack.push([node.right, level + 1]);
993
+ if (node && node.left)
994
+ stack.push([node.left, level + 1]);
995
+ }
909
996
  }
910
997
  }
911
998
  return levelsNodes;
@@ -114,9 +114,10 @@ export declare abstract class AbstractGraph<V = any, E = any, VO extends Abstrac
114
114
  * @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
115
115
  * It is the starting vertex for finding paths.
116
116
  * @param {VO | VertexKey} v2 - The parameter `v2` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
117
+ * @param limit - The count of limitation of result array.
117
118
  * @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`VO[][]`).
118
119
  */
119
- getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey): VO[][];
120
+ getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey, limit?: number): VO[][];
120
121
  /**
121
122
  * The function calculates the sum of weights along a given path.
122
123
  * @param {VO[]} path - An array of vertices (VO) representing a path in a graph.
@@ -148,10 +149,13 @@ export declare abstract class AbstractGraph<V = any, E = any, VO extends Abstrac
148
149
  * @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
149
150
  * minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
150
151
  * to false, the function will use breadth-first search (BFS) to find the minimum path.
152
+ * @param isDFS - If set to true, it enforces the use of getAllPathsBetween to first obtain all possible paths,
153
+ * followed by iterative computation of the shortest path. This approach may result in exponential time complexity,
154
+ * so the default method is to use the Dijkstra algorithm to obtain the shortest weighted path.
151
155
  * @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between
152
156
  * two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
153
157
  */
154
- getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): VO[] | null;
158
+ getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS?: boolean): VO[] | null;
155
159
  /**
156
160
  * Dijkstra algorithm time: O(VE) space: O(VO + EO)
157
161
  * /
@@ -4,8 +4,8 @@ exports.AbstractGraph = exports.AbstractEdge = exports.AbstractVertex = void 0;
4
4
  /**
5
5
  * data-structure-typed
6
6
  *
7
- * @author Kirk Qi
8
- * @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
7
+ * @author Tyler Zeng
8
+ * @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
9
9
  * @license MIT License
10
10
  */
11
11
  const utils_1 = require("../../utils");
@@ -162,31 +162,33 @@ class AbstractGraph {
162
162
  * @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
163
163
  * It is the starting vertex for finding paths.
164
164
  * @param {VO | VertexKey} v2 - The parameter `v2` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
165
+ * @param limit - The count of limitation of result array.
165
166
  * @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`VO[][]`).
166
167
  */
167
- getAllPathsBetween(v1, v2) {
168
+ getAllPathsBetween(v1, v2, limit = 1000) {
168
169
  const paths = [];
169
170
  const vertex1 = this._getVertex(v1);
170
171
  const vertex2 = this._getVertex(v2);
171
172
  if (!(vertex1 && vertex2)) {
172
173
  return [];
173
174
  }
174
- const dfs = (cur, dest, visiting, path) => {
175
- visiting.add(cur);
176
- if (cur === dest) {
177
- paths.push([vertex1, ...path]);
175
+ const stack = [];
176
+ stack.push({ vertex: vertex1, path: [vertex1] });
177
+ while (stack.length > 0) {
178
+ const { vertex, path } = stack.pop();
179
+ if (vertex === vertex2) {
180
+ paths.push(path);
181
+ if (paths.length >= limit)
182
+ return paths;
178
183
  }
179
- const neighbors = this.getNeighbors(cur);
184
+ const neighbors = this.getNeighbors(vertex);
180
185
  for (const neighbor of neighbors) {
181
- if (!visiting.has(neighbor)) {
182
- path.push(neighbor);
183
- dfs(neighbor, dest, visiting, path);
184
- path.pop();
186
+ if (!path.includes(neighbor)) {
187
+ const newPath = [...path, neighbor];
188
+ stack.push({ vertex: neighbor, path: newPath });
185
189
  }
186
190
  }
187
- visiting.delete(cur);
188
- };
189
- dfs(vertex1, vertex2, new Set(), []);
191
+ }
190
192
  return paths;
191
193
  }
192
194
  /**
@@ -270,52 +272,60 @@ class AbstractGraph {
270
272
  * @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
271
273
  * minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
272
274
  * to false, the function will use breadth-first search (BFS) to find the minimum path.
275
+ * @param isDFS - If set to true, it enforces the use of getAllPathsBetween to first obtain all possible paths,
276
+ * followed by iterative computation of the shortest path. This approach may result in exponential time complexity,
277
+ * so the default method is to use the Dijkstra algorithm to obtain the shortest weighted path.
273
278
  * @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between
274
279
  * two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
275
280
  */
276
- getMinPathBetween(v1, v2, isWeight) {
281
+ getMinPathBetween(v1, v2, isWeight, isDFS = false) {
282
+ var _a, _b;
277
283
  if (isWeight === undefined)
278
284
  isWeight = false;
279
285
  if (isWeight) {
280
- const allPaths = this.getAllPathsBetween(v1, v2);
281
- let min = Infinity;
282
- let minIndex = -1;
283
- let index = 0;
284
- for (const path of allPaths) {
285
- const pathSumWeight = this.getPathSumWeight(path);
286
- if (pathSumWeight < min) {
287
- min = pathSumWeight;
288
- minIndex = index;
286
+ if (isDFS) {
287
+ const allPaths = this.getAllPathsBetween(v1, v2, 10000);
288
+ let min = Infinity;
289
+ let minIndex = -1;
290
+ let index = 0;
291
+ for (const path of allPaths) {
292
+ const pathSumWeight = this.getPathSumWeight(path);
293
+ if (pathSumWeight < min) {
294
+ min = pathSumWeight;
295
+ minIndex = index;
296
+ }
297
+ index++;
289
298
  }
290
- index++;
299
+ return allPaths[minIndex] || null;
300
+ }
301
+ else {
302
+ return (_b = (_a = this.dijkstra(v1, v2, true, true)) === null || _a === void 0 ? void 0 : _a.minPath) !== null && _b !== void 0 ? _b : [];
291
303
  }
292
- return allPaths[minIndex] || null;
293
304
  }
294
305
  else {
295
- // BFS
306
+ // DFS
296
307
  let minPath = [];
297
308
  const vertex1 = this._getVertex(v1);
298
309
  const vertex2 = this._getVertex(v2);
299
- if (!(vertex1 && vertex2)) {
310
+ if (!(vertex1 && vertex2))
300
311
  return [];
301
- }
302
312
  const dfs = (cur, dest, visiting, path) => {
303
- visiting.set(cur, true);
313
+ visiting.add(cur);
304
314
  if (cur === dest) {
305
315
  minPath = [vertex1, ...path];
306
316
  return;
307
317
  }
308
318
  const neighbors = this.getNeighbors(cur);
309
319
  for (const neighbor of neighbors) {
310
- if (!visiting.get(neighbor)) {
320
+ if (!visiting.has(neighbor)) {
311
321
  path.push(neighbor);
312
322
  dfs(neighbor, dest, visiting, path);
313
- (0, utils_1.arrayRemove)(path, (vertex) => vertex === neighbor);
323
+ path.pop();
314
324
  }
315
325
  }
316
- visiting.set(cur, false);
326
+ visiting.delete(cur);
317
327
  };
318
- dfs(vertex1, vertex2, new Map(), []);
328
+ dfs(vertex1, vertex2, new Set(), []);
319
329
  return minPath;
320
330
  }
321
331
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "min-heap-typed",
3
- "version": "1.41.8",
3
+ "version": "1.42.0",
4
4
  "description": "Min Heap. Javascript & Typescript Data Structure.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -132,6 +132,6 @@
132
132
  "typescript": "^4.9.5"
133
133
  },
134
134
  "dependencies": {
135
- "data-structure-typed": "^1.41.8"
135
+ "data-structure-typed": "^1.42.0"
136
136
  }
137
137
  }
@@ -108,8 +108,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
108
108
  * @template N - The type of the binary tree's nodes.
109
109
  */
110
110
  export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
111
- implements IBinaryTree<V, N>
112
- {
111
+ implements IBinaryTree<V, N> {
113
112
  iterationType: IterationType = IterationType.ITERATIVE;
114
113
 
115
114
  /**
@@ -391,7 +390,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
391
390
  return -1;
392
391
  }
393
392
 
394
- const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}];
393
+ const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}];
395
394
  let maxHeight = 0;
396
395
 
397
396
  while (stack.length > 0) {
@@ -846,6 +845,27 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
846
845
  return this.isSubtreeBST(this.root, iterationType);
847
846
  }
848
847
 
848
+ subTreeTraverse<C extends BTNCallback<N>>(
849
+ callback?: C,
850
+ beginRoot?: BTNKey | N | null,
851
+ iterationType?: IterationType,
852
+ includeNull?: false
853
+ ): ReturnType<C>[]
854
+
855
+ subTreeTraverse<C extends BTNCallback<N>>(
856
+ callback?: C,
857
+ beginRoot?: BTNKey | N | null,
858
+ iterationType?: IterationType,
859
+ includeNull?: undefined
860
+ ): ReturnType<C>[]
861
+
862
+ subTreeTraverse<C extends BTNCallback<N | null>>(
863
+ callback?: C,
864
+ beginRoot?: BTNKey | N | null,
865
+ iterationType?: IterationType,
866
+ includeNull?: true
867
+ ): ReturnType<C>[]
868
+
849
869
  /**
850
870
  * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
851
871
  * node, either recursively or iteratively.
@@ -858,40 +878,79 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
858
878
  * start from the root of the tree.
859
879
  * @param iterationType - The `iterationType` parameter determines the type of traversal to be
860
880
  * performed on the binary tree. It can have two possible values:
881
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
861
882
  * @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
862
883
  */
863
- subTreeTraverse<C extends BTNCallback<N>>(
884
+ subTreeTraverse<C extends BTNCallback<N | null>>(
864
885
  callback: C = this.defaultOneParamCallback as C,
865
886
  beginRoot: BTNKey | N | null = this.root,
866
- iterationType = this.iterationType
887
+ iterationType = this.iterationType,
888
+ includeNull = false
867
889
  ): ReturnType<C>[] {
868
890
  if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
869
891
 
870
- const ans: ReturnType<BTNCallback<N>>[] = [];
892
+ const ans: (ReturnType<BTNCallback<N>> | null)[] = [];
871
893
  if (!beginRoot) return ans;
872
894
 
873
895
  if (iterationType === IterationType.RECURSIVE) {
874
- const _traverse = (cur: N) => {
875
- ans.push(callback(cur));
876
- cur.left && _traverse(cur.left);
877
- cur.right && _traverse(cur.right);
896
+ const _traverse = (cur: N | null) => {
897
+ if (cur !== undefined) {
898
+ ans.push(callback(cur));
899
+ if (includeNull) {
900
+ cur !== null && cur.left !== undefined && _traverse(cur.left);
901
+ cur !== null && cur.right !== undefined && _traverse(cur.right);
902
+ } else {
903
+ cur !== null && cur.left && _traverse(cur.left);
904
+ cur !== null && cur.right && _traverse(cur.right);
905
+ }
906
+ }
878
907
  };
879
908
 
880
909
  _traverse(beginRoot);
881
910
  } else {
882
- const stack: N[] = [beginRoot];
911
+ const stack: (N| null)[] = [beginRoot];
883
912
 
884
913
  while (stack.length > 0) {
885
- const cur = stack.pop()!;
886
-
887
- ans.push(callback(cur));
888
- cur.right && stack.push(cur.right);
889
- cur.left && stack.push(cur.left);
914
+ const cur = stack.pop();
915
+ if (cur !== undefined) {
916
+ ans.push(callback(cur));
917
+ if (includeNull) {
918
+ cur !== null && cur.right !== undefined && stack.push(cur.right);
919
+ cur !== null && cur.left !== undefined && stack.push(cur.left);
920
+ } else {
921
+ cur !== null && cur.right && stack.push(cur.right);
922
+ cur !== null && cur.left && stack.push(cur.left);
923
+ }
924
+ }
890
925
  }
891
926
  }
892
927
  return ans;
893
928
  }
894
929
 
930
+ dfs<C extends BTNCallback<N>>(
931
+ callback?: C,
932
+ pattern?: DFSOrderPattern,
933
+ beginRoot?: N | null,
934
+ iterationType?: IterationType,
935
+ includeNull?: false
936
+ ): ReturnType<C>[]
937
+
938
+ dfs<C extends BTNCallback<N>>(
939
+ callback?: C,
940
+ pattern?: DFSOrderPattern,
941
+ beginRoot?: N | null,
942
+ iterationType?: IterationType,
943
+ includeNull?: undefined
944
+ ): ReturnType<C>[]
945
+
946
+ dfs<C extends BTNCallback<N | null>>(
947
+ callback?: C,
948
+ pattern?: DFSOrderPattern,
949
+ beginRoot?: N | null,
950
+ iterationType?: IterationType,
951
+ includeNull?: true
952
+ ): ReturnType<C>[]
953
+
895
954
  /**
896
955
  * The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback
897
956
  * function on each node according to a specified order pattern.
@@ -905,34 +964,53 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
905
964
  * is `null`, an empty array will be returned.
906
965
  * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
907
966
  * iteration used in the depth-first search algorithm. It can have two possible values:
967
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
908
968
  * @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
909
969
  */
910
- dfs<C extends BTNCallback<N>>(
970
+ dfs<C extends BTNCallback<N | null>>(
911
971
  callback: C = this.defaultOneParamCallback as C,
912
972
  pattern: DFSOrderPattern = 'in',
913
973
  beginRoot: N | null = this.root,
914
- iterationType: IterationType = IterationType.ITERATIVE
974
+ iterationType: IterationType = IterationType.ITERATIVE,
975
+ includeNull = false
915
976
  ): ReturnType<C>[] {
916
977
  if (!beginRoot) return [];
917
- const ans: ReturnType<BTNCallback<N>>[] = [];
978
+ const ans: ReturnType<C>[] = [];
918
979
  if (iterationType === IterationType.RECURSIVE) {
919
- const _traverse = (node: N) => {
980
+ const _traverse = (node: N | null) => {
920
981
  switch (pattern) {
921
982
  case 'in':
922
- if (node.left) _traverse(node.left);
923
- ans.push(callback(node));
924
- if (node.right) _traverse(node.right);
983
+ if (includeNull) {
984
+ if (node !== null && node.left !== undefined) _traverse(node.left);
985
+ ans.push(callback(node));
986
+ if (node !== null && node.right !== undefined) _traverse(node.right);
987
+ } else {
988
+ if (node !== null && node.left) _traverse(node.left);
989
+ ans.push(callback(node));
990
+ if (node !== null && node.right) _traverse(node.right);
991
+ }
925
992
  break;
926
993
  case 'pre':
927
- ans.push(callback(node));
928
-
929
- if (node.left) _traverse(node.left);
930
- if (node.right) _traverse(node.right);
994
+ if (includeNull) {
995
+ ans.push(callback(node));
996
+ if (node !== null && node.left !== undefined) _traverse(node.left);
997
+ if (node !== null && node.right !== undefined) _traverse(node.right);
998
+ } else {
999
+ ans.push(callback(node));
1000
+ if (node !== null && node.left) _traverse(node.left);
1001
+ if (node !== null && node.right) _traverse(node.right);
1002
+ }
931
1003
  break;
932
1004
  case 'post':
933
- if (node.left) _traverse(node.left);
934
- if (node.right) _traverse(node.right);
935
- ans.push(callback(node));
1005
+ if (includeNull) {
1006
+ if (node !== null && node.left !== undefined) _traverse(node.left);
1007
+ if (node !== null && node.right !== undefined) _traverse(node.right);
1008
+ ans.push(callback(node));
1009
+ } else {
1010
+ if (node !== null && node.left) _traverse(node.left);
1011
+ if (node !== null && node.right) _traverse(node.right);
1012
+ ans.push(callback(node));
1013
+ }
936
1014
 
937
1015
  break;
938
1016
  }
@@ -941,34 +1019,39 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
941
1019
  _traverse(beginRoot);
942
1020
  } else {
943
1021
  // 0: visit, 1: print
944
- const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}];
1022
+ const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}];
945
1023
 
946
1024
  while (stack.length > 0) {
947
1025
  const cur = stack.pop();
948
- if (!cur || !cur.node) continue;
1026
+ if (cur === undefined) continue;
1027
+ if (includeNull) {
1028
+ if (cur.node === undefined) continue;
1029
+ } else {
1030
+ if (cur.node === null || cur.node === undefined) continue;
1031
+ }
949
1032
  if (cur.opt === 1) {
950
1033
  ans.push(callback(cur.node));
951
1034
  } else {
952
1035
  switch (pattern) {
953
1036
  case 'in':
954
- stack.push({opt: 0, node: cur.node.right});
1037
+ cur.node && stack.push({opt: 0, node: cur.node.right});
955
1038
  stack.push({opt: 1, node: cur.node});
956
- stack.push({opt: 0, node: cur.node.left});
1039
+ cur.node && stack.push({opt: 0, node: cur.node.left});
957
1040
  break;
958
1041
  case 'pre':
959
- stack.push({opt: 0, node: cur.node.right});
960
- stack.push({opt: 0, node: cur.node.left});
1042
+ cur.node && stack.push({opt: 0, node: cur.node.right});
1043
+ cur.node && stack.push({opt: 0, node: cur.node.left});
961
1044
  stack.push({opt: 1, node: cur.node});
962
1045
  break;
963
1046
  case 'post':
964
1047
  stack.push({opt: 1, node: cur.node});
965
- stack.push({opt: 0, node: cur.node.right});
966
- stack.push({opt: 0, node: cur.node.left});
1048
+ cur.node && stack.push({opt: 0, node: cur.node.right});
1049
+ cur.node && stack.push({opt: 0, node: cur.node.left});
967
1050
  break;
968
1051
  default:
969
- stack.push({opt: 0, node: cur.node.right});
1052
+ cur.node && stack.push({opt: 0, node: cur.node.right});
970
1053
  stack.push({opt: 1, node: cur.node});
971
- stack.push({opt: 0, node: cur.node.left});
1054
+ cur.node && stack.push({opt: 0, node: cur.node.left});
972
1055
  break;
973
1056
  }
974
1057
  }
@@ -978,6 +1061,27 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
978
1061
  return ans;
979
1062
  }
980
1063
 
1064
+ bfs<C extends BTNCallback<N>>(
1065
+ callback?: C,
1066
+ beginRoot?: N | null,
1067
+ iterationType?: IterationType,
1068
+ includeNull?: false
1069
+ ): ReturnType<C>[]
1070
+
1071
+ bfs<C extends BTNCallback<N>>(
1072
+ callback?: C,
1073
+ beginRoot?: N | null,
1074
+ iterationType?: IterationType,
1075
+ includeNull?: undefined
1076
+ ): ReturnType<C>[]
1077
+
1078
+ bfs<C extends BTNCallback<N | null>>(
1079
+ callback?: C,
1080
+ beginRoot?: N | null,
1081
+ iterationType?: IterationType,
1082
+ includeNull?: true
1083
+ ): ReturnType<C>[]
1084
+
981
1085
  /**
982
1086
  * The bfs function performs a breadth-first search traversal on a binary tree, executing a callback
983
1087
  * function on each node.
@@ -989,19 +1093,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
989
1093
  * will not be performed and an empty array will be returned.
990
1094
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be used
991
1095
  * in the breadth-first search (BFS) algorithm. It can have two possible values:
1096
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
992
1097
  * @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
993
1098
  */
994
- bfs<C extends BTNCallback<N>>(
1099
+ bfs<C extends BTNCallback<N | null>>(
995
1100
  callback: C = this.defaultOneParamCallback as C,
996
1101
  beginRoot: N | null = this.root,
997
- iterationType = this.iterationType
1102
+ iterationType = this.iterationType,
1103
+ includeNull = false
998
1104
  ): ReturnType<C>[] {
999
1105
  if (!beginRoot) return [];
1000
1106
 
1001
1107
  const ans: ReturnType<BTNCallback<N>>[] = [];
1002
1108
 
1003
1109
  if (iterationType === IterationType.RECURSIVE) {
1004
- const queue = new Queue<N>([beginRoot]);
1110
+ const queue: Queue<N | null> = new Queue<N | null>([beginRoot]);
1005
1111
 
1006
1112
  const traverse = (level: number) => {
1007
1113
  if (queue.size === 0) return;
@@ -1009,15 +1115,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1009
1115
  const current = queue.shift()!;
1010
1116
  ans.push(callback(current));
1011
1117
 
1012
- if (current.left) queue.push(current.left);
1013
- if (current.right) queue.push(current.right);
1118
+ if (includeNull) {
1119
+ if (current && current.left !== undefined) queue.push(current.left);
1120
+ if (current && current.right !== undefined) queue.push(current.right);
1121
+ } else {
1122
+ if (current.left) queue.push(current.left);
1123
+ if (current.right) queue.push(current.right);
1124
+ }
1125
+
1014
1126
 
1015
1127
  traverse(level + 1);
1016
1128
  };
1017
1129
 
1018
1130
  traverse(0);
1019
1131
  } else {
1020
- const queue = new Queue<N>([beginRoot]);
1132
+ const queue = new Queue<N | null>([beginRoot]);
1021
1133
  while (queue.size > 0) {
1022
1134
  const levelSize = queue.size;
1023
1135
 
@@ -1025,14 +1137,41 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1025
1137
  const current = queue.shift()!;
1026
1138
  ans.push(callback(current));
1027
1139
 
1028
- if (current.left) queue.push(current.left);
1029
- if (current.right) queue.push(current.right);
1140
+ if (includeNull) {
1141
+ if (current !== null && current.left !== undefined) queue.push(current.left);
1142
+ if (current !== null && current.right !== undefined) queue.push(current.right);
1143
+ } else {
1144
+ if (current.left) queue.push(current.left);
1145
+ if (current.right) queue.push(current.right);
1146
+ }
1147
+
1030
1148
  }
1031
1149
  }
1032
1150
  }
1033
1151
  return ans;
1034
1152
  }
1035
1153
 
1154
+ listLevels<C extends BTNCallback<N>>(
1155
+ callback?: C ,
1156
+ beginRoot?: N | null ,
1157
+ iterationType?: IterationType,
1158
+ includeNull?: false
1159
+ ): ReturnType<C>[][]
1160
+
1161
+ listLevels<C extends BTNCallback<N>>(
1162
+ callback?: C ,
1163
+ beginRoot?: N | null ,
1164
+ iterationType?: IterationType,
1165
+ includeNull?: undefined
1166
+ ): ReturnType<C>[][]
1167
+
1168
+ listLevels<C extends BTNCallback<N | null>>(
1169
+ callback?: C ,
1170
+ beginRoot?: N | null ,
1171
+ iterationType?: IterationType,
1172
+ includeNull?: true
1173
+ ): ReturnType<C>[][]
1174
+
1036
1175
  /**
1037
1176
  * The `listLevels` function takes a binary tree node and a callback function, and returns an array
1038
1177
  * of arrays representing the levels of the tree.
@@ -1044,29 +1183,36 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1044
1183
  * from the root node of the binary tree.
1045
1184
  * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done
1046
1185
  * recursively or iteratively. It can have two possible values:
1186
+ * @param includeNull - The choice to output null values during binary tree traversal should be provided.
1047
1187
  * @returns The function `listLevels` returns an array of arrays, where each inner array represents a
1048
1188
  * level in a binary tree. Each inner array contains the return type of the provided callback
1049
1189
  * function `C` applied to the nodes at that level.
1050
1190
  */
1051
- listLevels<C extends BTNCallback<N>>(
1191
+ listLevels<C extends BTNCallback<N | null>>(
1052
1192
  callback: C = this.defaultOneParamCallback as C,
1053
1193
  beginRoot: N | null = this.root,
1054
- iterationType = this.iterationType
1194
+ iterationType = this.iterationType,
1195
+ includeNull = false
1055
1196
  ): ReturnType<C>[][] {
1056
1197
  if (!beginRoot) return [];
1057
1198
  const levelsNodes: ReturnType<C>[][] = [];
1058
1199
 
1059
1200
  if (iterationType === IterationType.RECURSIVE) {
1060
- const _recursive = (node: N, level: number) => {
1201
+ const _recursive = (node: N | null, level: number) => {
1061
1202
  if (!levelsNodes[level]) levelsNodes[level] = [];
1062
1203
  levelsNodes[level].push(callback(node));
1063
- if (node.left) _recursive(node.left, level + 1);
1064
- if (node.right) _recursive(node.right, level + 1);
1204
+ if (includeNull) {
1205
+ if (node && node.left !== undefined) _recursive(node.left, level + 1);
1206
+ if (node && node.right !== undefined) _recursive(node.right, level + 1);
1207
+ } else {
1208
+ if (node && node.left) _recursive(node.left, level + 1);
1209
+ if (node && node.right) _recursive(node.right, level + 1);
1210
+ }
1065
1211
  };
1066
1212
 
1067
1213
  _recursive(beginRoot, 0);
1068
1214
  } else {
1069
- const stack: [N, number][] = [[beginRoot, 0]];
1215
+ const stack: [N | null, number][] = [[beginRoot, 0]];
1070
1216
 
1071
1217
  while (stack.length > 0) {
1072
1218
  const head = stack.pop()!;
@@ -1074,8 +1220,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1074
1220
 
1075
1221
  if (!levelsNodes[level]) levelsNodes[level] = [];
1076
1222
  levelsNodes[level].push(callback(node));
1077
- if (node.right) stack.push([node.right, level + 1]);
1078
- if (node.left) stack.push([node.left, level + 1]);
1223
+
1224
+ if (includeNull) {
1225
+ if (node && node.right !== undefined) stack.push([node.right, level + 1]);
1226
+ if (node && node.left !== undefined) stack.push([node.left, level + 1]);
1227
+ } else {
1228
+ if (node && node.right) stack.push([node.right, level + 1]);
1229
+ if (node && node.left) stack.push([node.left, level + 1]);
1230
+ }
1079
1231
  }
1080
1232
  }
1081
1233
 
@@ -1231,7 +1383,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1231
1383
  * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
1232
1384
  * binary tree nodes in a specific order.
1233
1385
  */
1234
- *[Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1386
+ * [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1235
1387
  if (!node) {
1236
1388
  return;
1237
1389
  }
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * data-structure-typed
3
3
  *
4
- * @author Kirk Qi
5
- * @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
4
+ * @author Tyler Zeng
5
+ * @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
6
6
  * @license MIT License
7
7
  */
8
- import {arrayRemove, uuidV4} from '../../utils';
8
+ import {uuidV4} from '../../utils';
9
9
  import {PriorityQueue} from '../priority-queue';
10
10
  import type {DijkstraResult, VertexKey} from '../../types';
11
11
  import {IGraph} from '../../interfaces';
@@ -223,39 +223,43 @@ export abstract class AbstractGraph<
223
223
  * @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
224
224
  * It is the starting vertex for finding paths.
225
225
  * @param {VO | VertexKey} v2 - The parameter `v2` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
226
+ * @param limit - The count of limitation of result array.
226
227
  * @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`VO[][]`).
227
228
  */
228
- getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey): VO[][] {
229
+ getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey, limit = 1000): VO[][] {
229
230
  const paths: VO[][] = [];
230
231
  const vertex1 = this._getVertex(v1);
231
232
  const vertex2 = this._getVertex(v2);
233
+
232
234
  if (!(vertex1 && vertex2)) {
233
235
  return [];
234
236
  }
235
237
 
236
- const dfs = (cur: VO, dest: VO, visiting: Set<VO>, path: VO[]) => {
237
- visiting.add(cur);
238
+ const stack: { vertex: VO, path: VO[] }[] = [];
239
+ stack.push({ vertex: vertex1, path: [vertex1] });
240
+
241
+ while (stack.length > 0) {
242
+ const { vertex, path } = stack.pop()!;
238
243
 
239
- if (cur === dest) {
240
- paths.push([vertex1, ...path]);
244
+ if (vertex === vertex2) {
245
+ paths.push(path);
246
+ if (paths.length >= limit) return paths;
241
247
  }
242
248
 
243
- const neighbors = this.getNeighbors(cur);
249
+ const neighbors = this.getNeighbors(vertex);
244
250
  for (const neighbor of neighbors) {
245
- if (!visiting.has(neighbor)) {
246
- path.push(neighbor);
247
- dfs(neighbor, dest, visiting, path);
248
- path.pop();
251
+ if (!path.includes(neighbor)) {
252
+ const newPath = [...path, neighbor];
253
+ stack.push({ vertex: neighbor, path: newPath });
249
254
  }
250
255
  }
251
-
252
- visiting.delete(cur);
253
- };
254
-
255
- dfs(vertex1, vertex2, new Set<VO>(), []);
256
+ }
256
257
  return paths;
257
258
  }
258
259
 
260
+
261
+
262
+
259
263
  /**
260
264
  * The function calculates the sum of weights along a given path.
261
265
  * @param {VO[]} path - An array of vertices (VO) representing a path in a graph.
@@ -338,38 +342,43 @@ export abstract class AbstractGraph<
338
342
  * @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
339
343
  * minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
340
344
  * to false, the function will use breadth-first search (BFS) to find the minimum path.
345
+ * @param isDFS - If set to true, it enforces the use of getAllPathsBetween to first obtain all possible paths,
346
+ * followed by iterative computation of the shortest path. This approach may result in exponential time complexity,
347
+ * so the default method is to use the Dijkstra algorithm to obtain the shortest weighted path.
341
348
  * @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between
342
349
  * two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
343
350
  */
344
- getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): VO[] | null {
351
+ getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS = false): VO[] | null {
345
352
  if (isWeight === undefined) isWeight = false;
346
353
 
347
354
  if (isWeight) {
348
- const allPaths = this.getAllPathsBetween(v1, v2);
349
- let min = Infinity;
350
- let minIndex = -1;
351
- let index = 0;
352
- for (const path of allPaths) {
353
- const pathSumWeight = this.getPathSumWeight(path);
354
- if (pathSumWeight < min) {
355
- min = pathSumWeight;
356
- minIndex = index;
355
+ if (isDFS) {
356
+ const allPaths = this.getAllPathsBetween(v1, v2, 10000);
357
+ let min = Infinity;
358
+ let minIndex = -1;
359
+ let index = 0;
360
+ for (const path of allPaths) {
361
+ const pathSumWeight = this.getPathSumWeight(path);
362
+ if (pathSumWeight < min) {
363
+ min = pathSumWeight;
364
+ minIndex = index;
365
+ }
366
+ index++;
357
367
  }
358
- index++;
368
+ return allPaths[minIndex] || null;
369
+ } else {
370
+ return this.dijkstra(v1, v2, true, true)?.minPath ?? [];
359
371
  }
360
- return allPaths[minIndex] || null;
372
+
361
373
  } else {
362
- // BFS
374
+ // DFS
363
375
  let minPath: VO[] = [];
364
376
  const vertex1 = this._getVertex(v1);
365
377
  const vertex2 = this._getVertex(v2);
366
- if (!(vertex1 && vertex2)) {
367
- return [];
368
- }
369
-
370
- const dfs = (cur: VO, dest: VO, visiting: Map<VO, boolean>, path: VO[]) => {
371
- visiting.set(cur, true);
378
+ if (!(vertex1 && vertex2)) return [];
372
379
 
380
+ const dfs = (cur: VO, dest: VO, visiting: Set<VO>, path: VO[]) => {
381
+ visiting.add(cur);
373
382
  if (cur === dest) {
374
383
  minPath = [vertex1, ...path];
375
384
  return;
@@ -377,17 +386,17 @@ export abstract class AbstractGraph<
377
386
 
378
387
  const neighbors = this.getNeighbors(cur);
379
388
  for (const neighbor of neighbors) {
380
- if (!visiting.get(neighbor)) {
389
+ if (!visiting.has(neighbor)) {
381
390
  path.push(neighbor);
382
391
  dfs(neighbor, dest, visiting, path);
383
- arrayRemove(path, (vertex: VO) => vertex === neighbor);
392
+ path.pop();
384
393
  }
385
394
  }
386
395
 
387
- visiting.set(cur, false);
396
+ visiting.delete(cur);
388
397
  };
389
398
 
390
- dfs(vertex1, vertex2, new Map<VO, boolean>(), []);
399
+ dfs(vertex1, vertex2, new Set<VO>(), []);
391
400
  return minPath;
392
401
  }
393
402
  }