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.
- package/dist/data-structures/binary-tree/binary-tree.d.ts +12 -61
- package/dist/data-structures/binary-tree/binary-tree.js +137 -50
- package/dist/data-structures/graph/abstract-graph.d.ts +6 -2
- package/dist/data-structures/graph/abstract-graph.js +45 -35
- package/package.json +2 -2
- package/src/data-structures/binary-tree/binary-tree.ts +209 -57
- package/src/data-structures/graph/abstract-graph.ts +50 -41
|
@@ -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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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 (
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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 (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
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 (
|
|
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 (
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
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 (
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
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 (
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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 (
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
|
8
|
-
* @copyright Copyright (c) 2022
|
|
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
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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(
|
|
184
|
+
const neighbors = this.getNeighbors(vertex);
|
|
180
185
|
for (const neighbor of neighbors) {
|
|
181
|
-
if (!
|
|
182
|
-
path
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
min
|
|
288
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
320
|
+
if (!visiting.has(neighbor)) {
|
|
311
321
|
path.push(neighbor);
|
|
312
322
|
dfs(neighbor, dest, visiting, path);
|
|
313
|
-
|
|
323
|
+
path.pop();
|
|
314
324
|
}
|
|
315
325
|
}
|
|
316
|
-
visiting.
|
|
326
|
+
visiting.delete(cur);
|
|
317
327
|
};
|
|
318
|
-
dfs(vertex1, vertex2, new
|
|
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.
|
|
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.
|
|
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
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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
|
-
|
|
888
|
-
|
|
889
|
-
|
|
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<
|
|
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 (
|
|
923
|
-
|
|
924
|
-
|
|
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
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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 (
|
|
934
|
-
|
|
935
|
-
|
|
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 (
|
|
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 (
|
|
1013
|
-
|
|
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 (
|
|
1029
|
-
|
|
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 (
|
|
1064
|
-
|
|
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
|
-
|
|
1078
|
-
if (
|
|
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
|
|
5
|
-
* @copyright Copyright (c) 2022
|
|
4
|
+
* @author Tyler Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
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
|
|
237
|
-
|
|
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 (
|
|
240
|
-
paths.push(
|
|
244
|
+
if (vertex === vertex2) {
|
|
245
|
+
paths.push(path);
|
|
246
|
+
if (paths.length >= limit) return paths;
|
|
241
247
|
}
|
|
242
248
|
|
|
243
|
-
const neighbors = this.getNeighbors(
|
|
249
|
+
const neighbors = this.getNeighbors(vertex);
|
|
244
250
|
for (const neighbor of neighbors) {
|
|
245
|
-
if (!
|
|
246
|
-
path
|
|
247
|
-
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
min
|
|
356
|
-
|
|
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
|
-
|
|
368
|
+
return allPaths[minIndex] || null;
|
|
369
|
+
} else {
|
|
370
|
+
return this.dijkstra(v1, v2, true, true)?.minPath ?? [];
|
|
359
371
|
}
|
|
360
|
-
|
|
372
|
+
|
|
361
373
|
} else {
|
|
362
|
-
//
|
|
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.
|
|
389
|
+
if (!visiting.has(neighbor)) {
|
|
381
390
|
path.push(neighbor);
|
|
382
391
|
dfs(neighbor, dest, visiting, path);
|
|
383
|
-
|
|
392
|
+
path.pop();
|
|
384
393
|
}
|
|
385
394
|
}
|
|
386
395
|
|
|
387
|
-
visiting.
|
|
396
|
+
visiting.delete(cur);
|
|
388
397
|
};
|
|
389
398
|
|
|
390
|
-
dfs(vertex1, vertex2, new
|
|
399
|
+
dfs(vertex1, vertex2, new Set<VO>(), []);
|
|
391
400
|
return minPath;
|
|
392
401
|
}
|
|
393
402
|
}
|