diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4c657b..fef9aee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/README.md b/README.md
index 0b3571b..f26e3de 100644
--- a/README.md
+++ b/README.md
@@ -636,40 +636,40 @@ optimal approach to data structure design.
[//]: # (Start of Replace Section)
avl-tree
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add randomly | 30.65 | 32.63 | 3.52e-4 |
10,000 add & delete randomly | 66.84 | 14.96 | 0.00 |
10,000 addMany | 41.52 | 24.08 | 0.01 |
10,000 get | 26.85 | 37.24 | 4.74e-4 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add randomly | 30.74 | 32.53 | 7.33e-4 |
10,000 add & delete randomly | 67.99 | 14.71 | 0.00 |
10,000 addMany | 39.82 | 25.11 | 4.59e-4 |
10,000 get | 26.70 | 37.46 | 2.61e-4 |
binary-tree
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000 add randomly | 12.99 | 76.99 | 3.06e-4 |
1,000 add & delete randomly | 16.12 | 62.04 | 4.54e-4 |
1,000 addMany | 10.95 | 91.29 | 8.27e-4 |
1,000 get | 18.10 | 55.24 | 2.56e-4 |
1,000 dfs | 69.33 | 14.42 | 6.64e-4 |
1,000 bfs | 57.04 | 17.53 | 4.09e-4 |
1,000 morris | 37.14 | 26.93 | 3.56e-4 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000 add randomly | 12.91 | 77.44 | 5.52e-4 |
1,000 add & delete randomly | 15.90 | 62.88 | 1.24e-4 |
1,000 addMany | 10.72 | 93.27 | 1.52e-4 |
1,000 get | 18.39 | 54.39 | 2.28e-4 |
1,000 dfs | 71.58 | 13.97 | 0.00 |
1,000 bfs | 57.62 | 17.35 | 0.00 |
1,000 morris | 37.17 | 26.90 | 2.13e-4 |
bst
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add randomly | 29.60 | 33.79 | 3.76e-4 |
10,000 add & delete randomly | 67.45 | 14.83 | 0.00 |
10,000 addMany | 29.09 | 34.38 | 8.10e-4 |
10,000 get | 27.81 | 35.96 | 8.19e-4 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add randomly | 30.50 | 32.79 | 0.00 |
10,000 add & delete randomly | 68.35 | 14.63 | 8.92e-4 |
10,000 addMany | 29.41 | 34.00 | 9.96e-4 |
10,000 get | 28.27 | 35.37 | 5.46e-4 |
rb-tree
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
100,000 add randomly | 73.46 | 13.61 | 0.01 |
100,000 add & 1000 delete randomly | 81.35 | 12.29 | 0.01 |
100,000 getNode | 65.23 | 15.33 | 0.01 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
100,000 add randomly | 82.19 | 12.17 | 0.01 |
100,000 add & 1000 delete randomly | 99.74 | 10.03 | 0.03 |
100,000 getNode | 78.27 | 12.78 | 0.04 |
directed-graph
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000 addVertex | 0.10 | 9826.70 | 4.27e-6 |
1,000 addEdge | 6.37 | 156.88 | 3.98e-4 |
1,000 getVertex | 0.05 | 2.14e+4 | 9.10e-7 |
1,000 getEdge | 22.93 | 43.62 | 0.00 |
tarjan | 213.01 | 4.69 | 0.01 |
tarjan all | 213.98 | 4.67 | 0.00 |
topologicalSort | 174.06 | 5.74 | 0.01 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000 addVertex | 0.10 | 9687.71 | 1.14e-5 |
1,000 addEdge | 7.42 | 134.68 | 0.00 |
1,000 getVertex | 0.05 | 2.05e+4 | 9.33e-6 |
1,000 getEdge | 20.29 | 49.29 | 0.00 |
tarjan | 190.48 | 5.25 | 0.01 |
tarjan all | 190.72 | 5.24 | 0.00 |
topologicalSort | 161.21 | 6.20 | 0.02 |
heap
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add & pop | 4.65 | 214.97 | 1.07e-4 |
10,000 fib add & pop | 354.24 | 2.82 | 0.00 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 add & pop | 4.70 | 212.55 | 5.89e-4 |
10,000 fib add & pop | 366.96 | 2.73 | 0.02 |
doubly-linked-list
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 unshift | 226.92 | 4.41 | 0.05 |
1,000,000 unshift & shift | 169.36 | 5.90 | 0.04 |
1,000,000 insertBefore | 319.44 | 3.13 | 0.06 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 unshift | 226.42 | 4.42 | 0.04 |
1,000,000 unshift & shift | 163.14 | 6.13 | 0.01 |
1,000,000 insertBefore | 343.18 | 2.91 | 0.08 |
singly-linked-list
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 push & pop | 226.29 | 4.42 | 0.02 |
10,000 insertBefore | 252.65 | 3.96 | 0.01 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 push & pop | 217.34 | 4.60 | 0.01 |
10,000 insertBefore | 248.51 | 4.02 | 0.00 |
max-priority-queue
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 refill & poll | 11.64 | 85.91 | 2.88e-4 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
10,000 refill & poll | 11.65 | 85.81 | 3.52e-4 |
deque
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 push | 222.81 | 4.49 | 0.06 |
1,000,000 shift | 26.80 | 37.31 | 0.00 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 push | 224.57 | 4.45 | 0.04 |
1,000,000 shift | 25.15 | 39.77 | 0.00 |
queue
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 push | 45.90 | 21.79 | 0.01 |
1,000,000 push & shift | 81.24 | 12.31 | 0.00 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
1,000,000 push | 43.52 | 22.98 | 0.01 |
1,000,000 push & shift | 79.71 | 12.55 | 0.00 |
trie
-
test name | time taken (ms) | executions per sec | sample deviation |
---|
100,000 push | 59.03 | 16.94 | 0.01 |
100,000 getWords | 89.17 | 11.21 | 0.00 |
+
test name | time taken (ms) | executions per sec | sample deviation |
---|
100,000 push | 59.28 | 16.87 | 0.00 |
100,000 getWords | 106.79 | 9.36 | 0.00 |
[//]: # (End of Replace Section)
\ No newline at end of file
diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts
index 3147c5f..72a4560 100644
--- a/src/data-structures/graph/abstract-graph.ts
+++ b/src/data-structures/graph/abstract-graph.ts
@@ -64,8 +64,7 @@ export abstract class AbstractGraph<
E = any,
VO extends AbstractVertex = AbstractVertex,
EO extends AbstractEdge = AbstractEdge
-> implements IGraph
-{
+> implements IGraph {
protected _vertices: Map = new Map();
get vertices(): Map {
@@ -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 {
+ 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 {
+ 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`.
+ */
+ getCycles(): Map {
+ 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 {
+ 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;
diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts
index e70a3f8..74e497d 100644
--- a/test/unit/data-structures/binary-tree/binary-tree.test.ts
+++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts
@@ -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', () => {
diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts
index ff8b2ad..ded2fff 100644
--- a/test/unit/data-structures/graph/directed-graph.test.ts
+++ b/test/unit/data-structures/graph/directed-graph.test.ts
@@ -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)
+});
\ No newline at end of file
diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts
index a216e49..12855d5 100644
--- a/test/unit/data-structures/graph/undirected-graph.test.ts
+++ b/test/unit/data-structures/graph/undirected-graph.test.ts
@@ -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)
+});
\ No newline at end of file