[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:
Revone 2023-11-06 14:47:00 +08:00
parent f15792c529
commit 25b9e1e9e4
6 changed files with 157 additions and 46 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.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

View file

@ -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)

View file

@ -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;

View file

@ -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', () => {

View file

@ -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)
});

View file

@ -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)
});