[graph] The getAllPathsBetween method in the [graph] provides a 'limit' parameter to control this exponential time complexity method from entering into a deadlock state. The getMinPathsBetween method, by default, calls the Dijkstra method to avoid invoking the excessively high time complexity method, getAllPathsBetween.

This commit is contained in:
Revone 2023-11-04 21:23:02 +08:00
parent 5af93dda72
commit 62e55b84bd
6 changed files with 109 additions and 90 deletions

View file

@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.41.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.41.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes

View file

@ -658,40 +658,40 @@ optimal approach to data structure design.
[//]: # (Start of Replace Section)
<div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>avl-tree</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>32.75</td><td>30.53</td><td>9.04e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>69.59</td><td>14.37</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>42.07</td><td>23.77</td><td>8.58e-4</td></tr><tr><td>10,000 get</td><td>27.87</td><td>35.88</td><td>5.71e-4</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>30.29</td><td>33.01</td><td>3.64e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>68.10</td><td>14.68</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.54</td><td>25.29</td><td>4.07e-4</td></tr><tr><td>10,000 get</td><td>26.72</td><td>37.42</td><td>3.77e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>binary-tree</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>12.84</td><td>77.86</td><td>1.92e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>15.94</td><td>62.72</td><td>3.07e-4</td></tr><tr><td>1,000 addMany</td><td>10.59</td><td>94.45</td><td>1.67e-4</td></tr><tr><td>1,000 get</td><td>17.99</td><td>55.59</td><td>2.35e-4</td></tr><tr><td>1,000 dfs</td><td>70.17</td><td>14.25</td><td>8.83e-4</td></tr><tr><td>1,000 bfs</td><td>54.52</td><td>18.34</td><td>7.43e-4</td></tr><tr><td>1,000 morris</td><td>37.26</td><td>26.84</td><td>5.27e-4</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>12.88</td><td>77.63</td><td>1.02e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>15.90</td><td>62.88</td><td>1.08e-4</td></tr><tr><td>1,000 addMany</td><td>10.59</td><td>94.41</td><td>8.39e-5</td></tr><tr><td>1,000 get</td><td>18.01</td><td>55.53</td><td>1.95e-4</td></tr><tr><td>1,000 dfs</td><td>69.11</td><td>14.47</td><td>6.47e-4</td></tr><tr><td>1,000 bfs</td><td>54.42</td><td>18.38</td><td>4.20e-4</td></tr><tr><td>1,000 morris</td><td>37.14</td><td>26.92</td><td>2.27e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>bst</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>33.25</td><td>30.07</td><td>4.20e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>73.76</td><td>13.56</td><td>8.39e-4</td></tr><tr><td>10,000 addMany</td><td>29.96</td><td>33.38</td><td>4.40e-4</td></tr><tr><td>10,000 get</td><td>28.53</td><td>35.05</td><td>3.89e-4</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>28.48</td><td>35.11</td><td>2.29e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>64.82</td><td>15.43</td><td>0.01</td></tr><tr><td>10,000 addMany</td><td>28.74</td><td>34.80</td><td>9.06e-4</td></tr><tr><td>10,000 get</td><td>27.38</td><td>36.52</td><td>1.82e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>rb-tree</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add randomly</td><td>74.41</td><td>13.44</td><td>0.00</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>80.63</td><td>12.40</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>60.00</td><td>16.67</td><td>0.01</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add randomly</td><td>72.30</td><td>13.83</td><td>0.00</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>81.37</td><td>12.29</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>59.48</td><td>16.81</td><td>9.29e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>directed-graph</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>9856.40</td><td>1.79e-6</td></tr><tr><td>1,000 addEdge</td><td>6.21</td><td>160.96</td><td>8.40e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.16e+4</td><td>3.85e-7</td></tr><tr><td>1,000 getEdge</td><td>22.43</td><td>44.57</td><td>0.00</td></tr><tr><td>tarjan</td><td>219.40</td><td>4.56</td><td>0.03</td></tr><tr><td>tarjan all</td><td>214.21</td><td>4.67</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>172.46</td><td>5.80</td><td>0.00</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>9786.77</td><td>5.56e-7</td></tr><tr><td>1,000 addEdge</td><td>6.02</td><td>166.04</td><td>1.27e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.18e+4</td><td>3.02e-7</td></tr><tr><td>1,000 getEdge</td><td>23.41</td><td>42.71</td><td>0.00</td></tr><tr><td>tarjan</td><td>223.51</td><td>4.47</td><td>0.01</td></tr><tr><td>tarjan all</td><td>224.89</td><td>4.45</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>181.90</td><td>5.50</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>heap</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.63</td><td>215.75</td><td>4.05e-5</td></tr><tr><td>10,000 fib add & pop</td><td>355.10</td><td>2.82</td><td>0.00</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.62</td><td>216.33</td><td>3.06e-5</td></tr><tr><td>10,000 fib add & pop</td><td>351.41</td><td>2.85</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>doubly-linked-list</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 unshift</td><td>210.62</td><td>4.75</td><td>0.05</td></tr><tr><td>1,000,000 unshift & shift</td><td>176.63</td><td>5.66</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>288.55</td><td>3.47</td><td>0.05</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 unshift</td><td>214.84</td><td>4.65</td><td>0.04</td></tr><tr><td>1,000,000 unshift & shift</td><td>167.11</td><td>5.98</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>335.78</td><td>2.98</td><td>0.07</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>singly-linked-list</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>232.24</td><td>4.31</td><td>0.03</td></tr><tr><td>10,000 insertBefore</td><td>245.58</td><td>4.07</td><td>0.00</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>212.53</td><td>4.71</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>243.94</td><td>4.10</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>max-priority-queue</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.62</td><td>86.09</td><td>2.24e-4</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.43</td><td>87.50</td><td>1.84e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>deque</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>223.78</td><td>4.47</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>25.79</td><td>38.78</td><td>0.00</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>216.07</td><td>4.63</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>24.97</td><td>40.05</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>queue</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>44.27</td><td>22.59</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>79.63</td><td>12.56</td><td>0.00</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>42.57</td><td>23.49</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>79.94</td><td>12.51</td><td>9.99e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>trie</span></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 push</td><td>49.29</td><td>20.29</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>95.55</td><td>10.47</td><td>0.01</td></tr></table></div>
<div class="content"><table><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 push</td><td>54.02</td><td>18.51</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>82.83</td><td>12.07</td><td>0.00</td></tr></table></div>
</div>
[//]: # (End of Replace Section)

50
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "data-structure-typed",
"version": "1.41.6",
"version": "1.41.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data-structure-typed",
"version": "1.41.6",
"version": "1.41.8",
"license": "MIT",
"devDependencies": {
"@types/benchmark": "^2.1.3",
@ -16,10 +16,10 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.41.6",
"avl-tree-typed": "^1.41.8",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.41.6",
"bst-typed": "^1.41.6",
"binary-tree-typed": "^1.41.8",
"bst-typed": "^1.41.8",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
@ -27,7 +27,7 @@
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"fast-glob": "^3.3.1",
"heap-typed": "^1.41.6",
"heap-typed": "^1.41.8",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",
@ -2789,12 +2789,12 @@
}
},
"node_modules/avl-tree-typed": {
"version": "1.41.6",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.41.6.tgz",
"integrity": "sha512-r7XvaFjgHKR1P/7YD8vC11p4MHgiDVzMU1vmIcQ44q0wxXkQ/YIncJhUSa7oM6PZpSoPRLk33wPpY3+1AUrnKQ==",
"version": "1.41.8",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.41.8.tgz",
"integrity": "sha512-tC0yAkPKS3TYj9q/PbEd+I/AgI/TZIcrueDXsKZMlpLwLe87oj2xfks50CRpmvF89iPHBWCgrtGO8YS1oF2/aw==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.41.6"
"data-structure-typed": "^1.41.8"
}
},
"node_modules/babel-jest": {
@ -2988,12 +2988,12 @@
}
},
"node_modules/binary-tree-typed": {
"version": "1.41.6",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.41.6.tgz",
"integrity": "sha512-B9FnRYxDIibvnKFnkm+zNwI62AwOPXMv0gQtAI6mvxuBYPUhy8tGGc5bZnQCisT/KFfrWwUj/1T72kgmyl4h1Q==",
"version": "1.41.8",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.41.8.tgz",
"integrity": "sha512-kViP86Bx1RGKz59KbKXZlRQL9KNsxX4rhPpR9Y1bQz0Tpz5JIuOBJk4f19YK+FdGQpIK3TzUPmFRDIJoHJLnxQ==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.41.6"
"data-structure-typed": "^1.41.8"
}
},
"node_modules/brace-expansion": {
@ -3072,12 +3072,12 @@
}
},
"node_modules/bst-typed": {
"version": "1.41.6",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.41.6.tgz",
"integrity": "sha512-GSiJ4JbszYhthcfPpu7+jyXNGzs94Il2111v94s288scZvvRCNjw7cBNUPScf2yAHJ6t4GMlz+ikPu4apoyA5g==",
"version": "1.41.8",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.41.8.tgz",
"integrity": "sha512-pOee++rWrVkub9+PSWMeyNNRae17iCVmu4tRy05ttGNCmb88aWgtCZgw+uNrsDj2WDUcwRbSO+usqvvc2kAqOg==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.41.6"
"data-structure-typed": "^1.41.8"
}
},
"node_modules/buffer-from": {
@ -3480,9 +3480,9 @@
}
},
"node_modules/data-structure-typed": {
"version": "1.41.6",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.41.6.tgz",
"integrity": "sha512-Yi7Kj5wQtjo/h6vE40dMOOma7BHc5ob3/Y6z0N3+zQjUpTUkYBN5jKl24RhxYVfWBCvWrK434prrxVMonwo0BA==",
"version": "1.41.8",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.41.8.tgz",
"integrity": "sha512-g4gwL7oJH6aMC8uD5Fgwgc/yRWDrVsnLpYtwpVk5A3FFWyIP/FXriQ0kNOdpo4TydSbefyjo/QzapUXHcZ7ZOA==",
"dev": true
},
"node_modules/debug": {
@ -4847,12 +4847,12 @@
}
},
"node_modules/heap-typed": {
"version": "1.41.6",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.41.6.tgz",
"integrity": "sha512-rrquP8vWOgEGWmF8aUmpYKKwFFu3+mk0eH0kwvlQr/dUybuHXf+JwzjBY9kvtaW1IuP8zhK9kK31mTPTjGs/Zw==",
"version": "1.41.8",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.41.8.tgz",
"integrity": "sha512-eegrUhG3a9EP9QHLCtjKmuWG3Fx6/wCSu4wGBIVgJP2OSSWdoGhp1Lj9BRqhCc6hYCLUlOEa271z458Y0vZmDw==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.41.6"
"data-structure-typed": "^1.41.8"
}
},
"node_modules/html-escaper": {

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.41.7",
"version": "1.41.9",
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
"main": "dist/cjs/src/index.js",
"module": "dist/mjs/src/index.js",
@ -64,10 +64,10 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.41.6",
"avl-tree-typed": "^1.41.8",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.41.6",
"bst-typed": "^1.41.6",
"binary-tree-typed": "^1.41.8",
"bst-typed": "^1.41.8",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
@ -75,7 +75,7 @@
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"fast-glob": "^3.3.1",
"heap-typed": "^1.41.6",
"heap-typed": "^1.41.8",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",

View file

@ -1,15 +1,16 @@
/**
* data-structure-typed
*
* @author Kirk Qi
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import {arrayRemove, uuidV4} from '../../utils';
import {uuidV4} from '../../utils';
import {PriorityQueue} from '../priority-queue';
import type {DijkstraResult, VertexKey} from '../../types';
import {IGraph} from '../../interfaces';
import {Queue} from '../queue';
import * as console from "console";
export abstract class AbstractVertex<V = any> {
key: VertexKey;
@ -223,39 +224,44 @@ export abstract class AbstractGraph<
* @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
* It is the starting vertex for finding paths.
* @param {VO | VertexKey} v2 - The parameter `v2` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`).
* @param limit - The count of limitation of result array.
* @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`VO[][]`).
*/
getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey): VO[][] {
getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey, limit = 1000): VO[][] {
const paths: VO[][] = [];
const vertex1 = this._getVertex(v1);
const vertex2 = this._getVertex(v2);
if (!(vertex1 && vertex2)) {
return [];
}
const dfs = (cur: VO, dest: VO, visiting: Set<VO>, path: VO[]) => {
visiting.add(cur);
const stack: { vertex: VO, path: VO[] }[] = [];
stack.push({ vertex: vertex1, path: [vertex1] });
if (cur === dest) {
paths.push([vertex1, ...path]);
while (stack.length > 0) {
const { vertex, path } = stack.pop()!;
if (vertex === vertex2) {
paths.push(path);
if (paths.length >= limit) return paths;
}
const neighbors = this.getNeighbors(cur);
const neighbors = this.getNeighbors(vertex);
for (const neighbor of neighbors) {
if (!visiting.has(neighbor)) {
path.push(neighbor);
dfs(neighbor, dest, visiting, path);
path.pop();
if (!path.includes(neighbor)) {
const newPath = [...path, neighbor];
stack.push({ vertex: neighbor, path: newPath });
}
}
visiting.delete(cur);
};
dfs(vertex1, vertex2, new Set<VO>(), []);
}
console.log('999999', JSON.stringify(paths));
return paths;
}
/**
* The function calculates the sum of weights along a given path.
* @param {VO[]} path - An array of vertices (VO) representing a path in a graph.
@ -338,38 +344,43 @@ export abstract class AbstractGraph<
* @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
* minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
* to false, the function will use breadth-first search (BFS) to find the minimum path.
* @param isDFS - If set to true, it enforces the use of getAllPathsBetween to first obtain all possible paths,
* followed by iterative computation of the shortest path. This approach may result in exponential time complexity,
* so the default method is to use the Dijkstra algorithm to obtain the shortest weighted path.
* @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between
* two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
*/
getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): VO[] | null {
getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean, isDFS = false): VO[] | null {
if (isWeight === undefined) isWeight = false;
if (isWeight) {
const allPaths = this.getAllPathsBetween(v1, v2);
let min = Infinity;
let minIndex = -1;
let index = 0;
for (const path of allPaths) {
const pathSumWeight = this.getPathSumWeight(path);
if (pathSumWeight < min) {
min = pathSumWeight;
minIndex = index;
if (isDFS) {
const allPaths = this.getAllPathsBetween(v1, v2, 10000);
let min = Infinity;
let minIndex = -1;
let index = 0;
for (const path of allPaths) {
const pathSumWeight = this.getPathSumWeight(path);
if (pathSumWeight < min) {
min = pathSumWeight;
minIndex = index;
}
index++;
}
index++;
return allPaths[minIndex] || null;
} else {
return this.dijkstra(v1, v2, true, true)?.minPath ?? [];
}
return allPaths[minIndex] || null;
} else {
// BFS
// DFS
let minPath: VO[] = [];
const vertex1 = this._getVertex(v1);
const vertex2 = this._getVertex(v2);
if (!(vertex1 && vertex2)) {
return [];
}
const dfs = (cur: VO, dest: VO, visiting: Map<VO, boolean>, path: VO[]) => {
visiting.set(cur, true);
if (!(vertex1 && vertex2)) return [];
const dfs = (cur: VO, dest: VO, visiting: Set<VO>, path: VO[]) => {
visiting.add(cur);
if (cur === dest) {
minPath = [vertex1, ...path];
return;
@ -377,17 +388,17 @@ export abstract class AbstractGraph<
const neighbors = this.getNeighbors(cur);
for (const neighbor of neighbors) {
if (!visiting.get(neighbor)) {
if (!visiting.has(neighbor)) {
path.push(neighbor);
dfs(neighbor, dest, visiting, path);
arrayRemove(path, (vertex: VO) => vertex === neighbor);
path.pop();
}
}
visiting.set(cur, false);
visiting.delete(cur);
};
dfs(vertex1, vertex2, new Map<VO, boolean>(), []);
dfs(vertex1, vertex2, new Set<VO>(), []);
return minPath;
}
}

View file

@ -149,8 +149,7 @@ describe('UndirectedGraph', () => {
expect(degreeOfC).toBe(1);
});
it('xxx', () => {
// const start = performance.now();
it('should getAllPathsBetween work well in 66 vertexes 97 edges graph', () => {
const graph = new UndirectedGraph<{name: string}, number>();
for (const v of saltyVertexes) {
graph.addVertex(v.name, v);
@ -159,9 +158,18 @@ describe('UndirectedGraph', () => {
const [s, d] = e;
graph.addEdge(s.name, d.name, d.weight);
}
// const result = graph.getAllPathsBetween('Intersection_1','Intersection_5');
// console.log('---xxx', performance.now() - start, result)
// const result = graph.dijkstra('Intersection_1','Intersection_5', true, true);
// console.log('---xxx', performance.now() - start, result)
const allPaths = graph.getAllPathsBetween('Intersection_1','Intersection_5');
expect(allPaths.length).toBe(1000);
const minWeightedPathDFS = graph.getMinPathBetween('Intersection_1','Intersection_5', true, true);
const minWeightedPath = graph.dijkstra('Intersection_1','Intersection_5', true, true);
expect(minWeightedPathDFS?.[0].key).toBe('Intersection_1');
expect(minWeightedPathDFS?.[5].key).toBe('Intersection_42');
expect(minWeightedPathDFS?.[8].key).toBe('Intersection_18');
expect(minWeightedPathDFS?.[31].key).toBe('Intersection_5');
expect(minWeightedPath?.minPath?.[0].key).toBe('Intersection_1')
expect(minWeightedPath?.minPath?.[1].key).toBe('Intersection_2')
expect(minWeightedPath?.minPath?.[2].key).toBe('Intersection_3')
expect(minWeightedPath?.minPath?.[3].key).toBe('Intersection_4')
expect(minWeightedPath?.minPath?.[4].key).toBe('Intersection_5')
});
});