mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
[graph] To facilitate users who are not familiar with the Tarjan algorithm, provide the following methods: getCycles, getSCCs, getBridges, getCutVertexes, getDFNMap, and getLowMap.
This commit is contained in:
parent
f15792c529
commit
25b9e1e9e4
|
@ -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.42.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
## [v1.42.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
|
|
24
README.md
24
README.md
|
@ -636,40 +636,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 style="display: table; width:100%; table-layout: fixed;"><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.65</td><td>32.63</td><td>3.52e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>66.84</td><td>14.96</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>41.52</td><td>24.08</td><td>0.01</td></tr><tr><td>10,000 get</td><td>26.85</td><td>37.24</td><td>4.74e-4</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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.74</td><td>32.53</td><td>7.33e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>67.99</td><td>14.71</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.82</td><td>25.11</td><td>4.59e-4</td></tr><tr><td>10,000 get</td><td>26.70</td><td>37.46</td><td>2.61e-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 style="display: table; width:100%; table-layout: fixed;"><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.99</td><td>76.99</td><td>3.06e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.12</td><td>62.04</td><td>4.54e-4</td></tr><tr><td>1,000 addMany</td><td>10.95</td><td>91.29</td><td>8.27e-4</td></tr><tr><td>1,000 get</td><td>18.10</td><td>55.24</td><td>2.56e-4</td></tr><tr><td>1,000 dfs</td><td>69.33</td><td>14.42</td><td>6.64e-4</td></tr><tr><td>1,000 bfs</td><td>57.04</td><td>17.53</td><td>4.09e-4</td></tr><tr><td>1,000 morris</td><td>37.14</td><td>26.93</td><td>3.56e-4</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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.91</td><td>77.44</td><td>5.52e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>15.90</td><td>62.88</td><td>1.24e-4</td></tr><tr><td>1,000 addMany</td><td>10.72</td><td>93.27</td><td>1.52e-4</td></tr><tr><td>1,000 get</td><td>18.39</td><td>54.39</td><td>2.28e-4</td></tr><tr><td>1,000 dfs</td><td>71.58</td><td>13.97</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>57.62</td><td>17.35</td><td>0.00</td></tr><tr><td>1,000 morris</td><td>37.17</td><td>26.90</td><td>2.13e-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 style="display: table; width:100%; table-layout: fixed;"><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>29.60</td><td>33.79</td><td>3.76e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>67.45</td><td>14.83</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>29.09</td><td>34.38</td><td>8.10e-4</td></tr><tr><td>10,000 get</td><td>27.81</td><td>35.96</td><td>8.19e-4</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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.50</td><td>32.79</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>68.35</td><td>14.63</td><td>8.92e-4</td></tr><tr><td>10,000 addMany</td><td>29.41</td><td>34.00</td><td>9.96e-4</td></tr><tr><td>10,000 get</td><td>28.27</td><td>35.37</td><td>5.46e-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 style="display: table; width:100%; table-layout: fixed;"><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>73.46</td><td>13.61</td><td>0.01</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>81.35</td><td>12.29</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>65.23</td><td>15.33</td><td>0.01</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>82.19</td><td>12.17</td><td>0.01</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>99.74</td><td>10.03</td><td>0.03</td></tr><tr><td>100,000 getNode</td><td>78.27</td><td>12.78</td><td>0.04</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 style="display: table; width:100%; table-layout: fixed;"><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>9826.70</td><td>4.27e-6</td></tr><tr><td>1,000 addEdge</td><td>6.37</td><td>156.88</td><td>3.98e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.14e+4</td><td>9.10e-7</td></tr><tr><td>1,000 getEdge</td><td>22.93</td><td>43.62</td><td>0.00</td></tr><tr><td>tarjan</td><td>213.01</td><td>4.69</td><td>0.01</td></tr><tr><td>tarjan all</td><td>213.98</td><td>4.67</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>174.06</td><td>5.74</td><td>0.01</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>9687.71</td><td>1.14e-5</td></tr><tr><td>1,000 addEdge</td><td>7.42</td><td>134.68</td><td>0.00</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.05e+4</td><td>9.33e-6</td></tr><tr><td>1,000 getEdge</td><td>20.29</td><td>49.29</td><td>0.00</td></tr><tr><td>tarjan</td><td>190.48</td><td>5.25</td><td>0.01</td></tr><tr><td>tarjan all</td><td>190.72</td><td>5.24</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>161.21</td><td>6.20</td><td>0.02</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 style="display: table; width:100%; table-layout: fixed;"><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.65</td><td>214.97</td><td>1.07e-4</td></tr><tr><td>10,000 fib add & pop</td><td>354.24</td><td>2.82</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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.70</td><td>212.55</td><td>5.89e-4</td></tr><tr><td>10,000 fib add & pop</td><td>366.96</td><td>2.73</td><td>0.02</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 style="display: table; width:100%; table-layout: fixed;"><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>226.92</td><td>4.41</td><td>0.05</td></tr><tr><td>1,000,000 unshift & shift</td><td>169.36</td><td>5.90</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>319.44</td><td>3.13</td><td>0.06</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>226.42</td><td>4.42</td><td>0.04</td></tr><tr><td>1,000,000 unshift & shift</td><td>163.14</td><td>6.13</td><td>0.01</td></tr><tr><td>1,000,000 insertBefore</td><td>343.18</td><td>2.91</td><td>0.08</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 style="display: table; width:100%; table-layout: fixed;"><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>226.29</td><td>4.42</td><td>0.02</td></tr><tr><td>10,000 insertBefore</td><td>252.65</td><td>3.96</td><td>0.01</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>217.34</td><td>4.60</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>248.51</td><td>4.02</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 style="display: table; width:100%; table-layout: fixed;"><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.64</td><td>85.91</td><td>2.88e-4</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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.65</td><td>85.81</td><td>3.52e-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 style="display: table; width:100%; table-layout: fixed;"><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>222.81</td><td>4.49</td><td>0.06</td></tr><tr><td>1,000,000 shift</td><td>26.80</td><td>37.31</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>224.57</td><td>4.45</td><td>0.04</td></tr><tr><td>1,000,000 shift</td><td>25.15</td><td>39.77</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 style="display: table; width:100%; table-layout: fixed;"><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>45.90</td><td>21.79</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>81.24</td><td>12.31</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>43.52</td><td>22.98</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>79.71</td><td>12.55</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'>trie</span></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>59.03</td><td>16.94</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>89.17</td><td>11.21</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><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>59.28</td><td>16.87</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>106.79</td><td>9.36</td><td>0.00</td></tr></table></div>
|
||||
</div>
|
||||
|
||||
[//]: # (End of Replace Section)
|
|
@ -64,8 +64,7 @@ export abstract class AbstractGraph<
|
|||
E = any,
|
||||
VO extends AbstractVertex<V> = AbstractVertex<V>,
|
||||
EO extends AbstractEdge<E> = AbstractEdge<E>
|
||||
> implements IGraph<V, E, VO, EO>
|
||||
{
|
||||
> implements IGraph<V, E, VO, EO> {
|
||||
protected _vertices: Map<VertexKey, VO> = new Map<VertexKey, VO>();
|
||||
|
||||
get vertices(): Map<VertexKey, VO> {
|
||||
|
@ -236,10 +235,10 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
const stack: { vertex: VO, path: VO[] }[] = [];
|
||||
stack.push({ vertex: vertex1, path: [vertex1] });
|
||||
stack.push({vertex: vertex1, path: [vertex1]});
|
||||
|
||||
while (stack.length > 0) {
|
||||
const { vertex, path } = stack.pop()!;
|
||||
const {vertex, path} = stack.pop()!;
|
||||
|
||||
if (vertex === vertex2) {
|
||||
paths.push(path);
|
||||
|
@ -250,7 +249,7 @@ export abstract class AbstractGraph<
|
|||
for (const neighbor of neighbors) {
|
||||
if (!path.includes(neighbor)) {
|
||||
const newPath = [...path, neighbor];
|
||||
stack.push({ vertex: neighbor, path: newPath });
|
||||
stack.push({vertex: neighbor, path: newPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,8 +257,6 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -522,14 +519,14 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
getMinDist &&
|
||||
distMap.forEach((d, v) => {
|
||||
if (v !== srcVertex) {
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
if (genPaths) minDest = v;
|
||||
}
|
||||
distMap.forEach((d, v) => {
|
||||
if (v !== srcVertex) {
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
if (genPaths) minDest = v;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
genPaths && getPaths(minDest);
|
||||
|
||||
|
@ -591,7 +588,7 @@ export abstract class AbstractGraph<
|
|||
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
|
||||
}
|
||||
|
||||
const heap = new PriorityQueue<{key: number; value: VO}>({comparator: (a, b) => a.key - b.key});
|
||||
const heap = new PriorityQueue<{ key: number; value: VO }>({comparator: (a, b) => a.key - b.key});
|
||||
heap.add({key: 0, value: srcVertex});
|
||||
|
||||
distMap.set(srcVertex, 0);
|
||||
|
@ -802,11 +799,6 @@ export abstract class AbstractGraph<
|
|||
* Floyd algorithm time: O(VO^3) space: O(VO^2), not support graph with negative weight cycle
|
||||
* all pairs
|
||||
* The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Floyd algorithm time: O(VO^3) space: O(VO^2), not support graph with negative weight cycle
|
||||
* all pairs
|
||||
* /
|
||||
|
||||
/**
|
||||
|
@ -815,12 +807,12 @@ export abstract class AbstractGraph<
|
|||
* The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes.
|
||||
* The function implements the Floyd-Warshall algorithm to find the shortest path between all pairs of vertices in a
|
||||
* graph.
|
||||
* @returns The function `floyd()` returns an object with two properties: `costs` and `predecessor`. The `costs`
|
||||
* @returns The function `floydWarshall()` returns an object with two properties: `costs` and `predecessor`. The `costs`
|
||||
* property is a 2D array of numbers representing the shortest path costs between vertices in a graph. The
|
||||
* `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest
|
||||
* path between vertices in the
|
||||
*/
|
||||
floyd(): {costs: number[][]; predecessor: (VO | null)[][]} {
|
||||
floydWarshall(): { costs: number[][]; predecessor: (VO | null)[][] } {
|
||||
const idAndVertices = [...this._vertices];
|
||||
const n = idAndVertices.length;
|
||||
|
||||
|
@ -871,7 +863,7 @@ export abstract class AbstractGraph<
|
|||
* Tarjan can find the SSC(strongly connected components), articulation points, and bridges of directed graphs.
|
||||
* The `tarjan` function is used to perform various graph analysis tasks such as finding articulation points, bridges,
|
||||
* strongly connected components (SCCs), and cycles in a graph.
|
||||
* @param {boolean} [needArticulationPoints] - A boolean value indicating whether or not to calculate and return the
|
||||
* @param {boolean} [needCutVertexes] - A boolean value indicating whether or not to calculate and return the
|
||||
* articulation points in the graph. Articulation points are the vertices in a graph whose removal would increase the
|
||||
* number of connected components in the graph.
|
||||
* @param {boolean} [needBridges] - A boolean flag indicating whether the algorithm should find and return the bridges
|
||||
|
@ -884,13 +876,13 @@ export abstract class AbstractGraph<
|
|||
* are arrays of vertices that form cycles within the SCCs.
|
||||
* @returns The function `tarjan` returns an object with the following properties:
|
||||
*/
|
||||
tarjan(needArticulationPoints?: boolean, needBridges?: boolean, needSCCs?: boolean, needCycles?: boolean) {
|
||||
tarjan(needCutVertexes: boolean = false, needBridges: boolean = false, needSCCs: boolean = true, needCycles: boolean = false) {
|
||||
// !! in undirected graph we will not let child visit parent when dfs
|
||||
// !! articulation point(in dfs search tree not in graph): (cur !== root && cur.has(child)) && (low(child) >= dfn(cur)) || (cur === root && cur.children() >= 2)
|
||||
// !! bridge: low(child) > dfn(cur)
|
||||
|
||||
const defaultConfig = false;
|
||||
if (needArticulationPoints === undefined) needArticulationPoints = defaultConfig;
|
||||
if (needCutVertexes === undefined) needCutVertexes = defaultConfig;
|
||||
if (needBridges === undefined) needBridges = defaultConfig;
|
||||
if (needSCCs === undefined) needSCCs = defaultConfig;
|
||||
if (needCycles === undefined) needCycles = defaultConfig;
|
||||
|
@ -905,7 +897,7 @@ export abstract class AbstractGraph<
|
|||
|
||||
const [root] = vertices.values();
|
||||
|
||||
const articulationPoints: VO[] = [];
|
||||
const cutVertexes: VO[] = [];
|
||||
const bridges: EO[] = [];
|
||||
let dfn = 0;
|
||||
const dfs = (cur: VO, parent: VO | null) => {
|
||||
|
@ -929,10 +921,10 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
const curFromMap = dfnMap.get(cur);
|
||||
if (childLow !== undefined && curFromMap !== undefined) {
|
||||
if (needArticulationPoints) {
|
||||
if (needCutVertexes) {
|
||||
if ((cur === root && childCount >= 2) || (cur !== root && childLow >= curFromMap)) {
|
||||
// todo not ensure the logic if (cur === root && childCount >= 2 || ((cur !== root) && (childLow >= curFromMap))) {
|
||||
articulationPoints.push(cur);
|
||||
cutVertexes.push(cur);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -983,7 +975,59 @@ export abstract class AbstractGraph<
|
|||
});
|
||||
}
|
||||
|
||||
return {dfnMap, lowMap, bridges, articulationPoints, SCCs, cycles};
|
||||
return {dfnMap, lowMap, bridges, cutVertexes, SCCs, cycles};
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns a map that associates each vertex object with its corresponding depth-first
|
||||
* number.
|
||||
* @returns A Map object with keys of type VO and values of type number.
|
||||
*/
|
||||
getDFNMap(): Map<VO, number> {
|
||||
return this.tarjan(false, false, false, false).dfnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns a Map object that contains the low values of each vertex in a Tarjan
|
||||
* algorithm.
|
||||
* @returns The method `getLowMap()` is returning a `Map` object with keys of type `VO` and values of
|
||||
* type `number`.
|
||||
*/
|
||||
getLowMap(): Map<VO, number> {
|
||||
return this.tarjan(false, false, false, false).lowMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `getCycles` returns a map of cycles found using the Tarjan algorithm.
|
||||
* @returns The function `getCycles()` is returning a `Map<number, VO[]>`.
|
||||
*/
|
||||
getCycles(): Map<number, VO[]> {
|
||||
return this.tarjan(false, false, false, true).cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "getCutVertexes" returns an array of cut vertexes using the Tarjan algorithm.
|
||||
* @returns an array of VO objects, specifically the cut vertexes.
|
||||
*/
|
||||
getCutVertexes(): VO[] {
|
||||
return this.tarjan(true, false, false, false).cutVertexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "getSCCs" returns a map of strongly connected components (SCCs) using the Tarjan
|
||||
* algorithm.
|
||||
* @returns a map where the keys are numbers and the values are arrays of VO objects.
|
||||
*/
|
||||
getSCCs(): Map<number, VO[]> {
|
||||
return this.tarjan(false, false, true, false).SCCs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "getBridges" returns an array of bridges using the Tarjan algorithm.
|
||||
* @returns the bridges found using the Tarjan algorithm.
|
||||
*/
|
||||
getBridges() {
|
||||
return this.tarjan(false, true, false, false).bridges;
|
||||
}
|
||||
|
||||
protected abstract _addEdgeOnly(edge: EO): boolean;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode, IterationType} from '../../../../src';
|
||||
import {isDebugTest} from '../../../config';
|
||||
// import {isDebugTest} from '../../../config';
|
||||
|
||||
const isDebug = isDebugTest;
|
||||
// const isDebug = true;
|
||||
// const isDebug = isDebugTest;
|
||||
|
||||
describe('BinaryTreeNode', () => {
|
||||
it('should create an instance of BinaryTreeNode', () => {
|
||||
|
|
|
@ -340,7 +340,7 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
|
|||
expect(min).toBe(Infinity);
|
||||
expect(minPath).toBeInstanceOf(Array);
|
||||
|
||||
const floydResult = myGraph.floyd();
|
||||
const floydResult = myGraph.floydWarshall();
|
||||
expect(floydResult).toBeTruthy();
|
||||
if (floydResult) {
|
||||
const {costs, predecessor} = floydResult;
|
||||
|
@ -562,3 +562,37 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('cycles, strongly connected components, bridges, articular points in DirectedGraph', () => {
|
||||
const graph = new DirectedGraph();
|
||||
graph.addVertex('A');
|
||||
graph.addVertex('B');
|
||||
graph.addVertex('C');
|
||||
graph.addVertex('D');
|
||||
graph.addVertex('E');
|
||||
graph.addVertex('F');
|
||||
graph.addVertex('G');
|
||||
graph.addVertex('H');
|
||||
graph.addEdge('A', 'B');
|
||||
graph.addEdge('B', 'D');
|
||||
graph.addEdge('D', 'C');
|
||||
graph.addEdge('C', 'A');
|
||||
graph.addEdge('C', 'B');
|
||||
graph.addEdge('D', 'E');
|
||||
graph.addEdge('E', 'G');
|
||||
graph.addEdge('E', 'H');
|
||||
graph.addEdge('H', 'F');
|
||||
const cycles = graph.getCycles();
|
||||
const scCs = graph.getSCCs();
|
||||
const bridges = graph.getBridges();
|
||||
const cutVertexes = graph.getCutVertexes();
|
||||
const dfnMap = graph.getDFNMap();
|
||||
const lowMap = graph.getLowMap();
|
||||
expect(cycles.size).toBe(1)
|
||||
expect(scCs.size).toBe(5)
|
||||
expect(bridges.length).toBe(4)
|
||||
expect(cutVertexes.length).toBe(4)
|
||||
expect(dfnMap.size).toBe(8)
|
||||
expect(lowMap.size).toBe(8)
|
||||
});
|
|
@ -174,3 +174,37 @@ describe('UndirectedGraph', () => {
|
|||
expect(minWeightedPath?.minPath?.[4]?.key).toBe('Intersection_5')
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('cycles, strongly connected components, bridges, articular points in UndirectedGraph', () => {
|
||||
const graph = new UndirectedGraph();
|
||||
graph.addVertex('A');
|
||||
graph.addVertex('B');
|
||||
graph.addVertex('C');
|
||||
graph.addVertex('D');
|
||||
graph.addVertex('E');
|
||||
graph.addVertex('F');
|
||||
graph.addVertex('G');
|
||||
graph.addVertex('H');
|
||||
graph.addEdge('A', 'B');
|
||||
graph.addEdge('B', 'D');
|
||||
graph.addEdge('D', 'C');
|
||||
graph.addEdge('C', 'A');
|
||||
graph.addEdge('C', 'B');
|
||||
graph.addEdge('D', 'E');
|
||||
graph.addEdge('E', 'G');
|
||||
graph.addEdge('E', 'H');
|
||||
graph.addEdge('H', 'F');
|
||||
const cycles = graph.getCycles();
|
||||
const scCs = graph.getSCCs();
|
||||
const bridges = graph.getBridges();
|
||||
const cutVertexes = graph.getCutVertexes();
|
||||
const dfnMap = graph.getDFNMap();
|
||||
const lowMap = graph.getLowMap();
|
||||
expect(cycles.size).toBe(1)
|
||||
expect(scCs.size).toBe(5)
|
||||
expect(bridges.length).toBe(4)
|
||||
expect(cutVertexes.length).toBe(4)
|
||||
expect(dfnMap.size).toBe(8)
|
||||
expect(lowMap.size).toBe(8)
|
||||
});
|
Loading…
Reference in a new issue