From 0394575158d1283997982a0d3a6a54109e02559a Mon Sep 17 00:00:00 2001 From: Adrito-M Date: Wed, 19 Oct 2022 19:34:28 +0530 Subject: [PATCH 1/5] kosaraju test added --- Graphs/Kosaraju.js | 90 ++++++++++++++++++++++++++++++++++++ Graphs/test/Kosaraju.test.js | 30 ++++++++++++ package-lock.json | 2 +- 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 Graphs/Kosaraju.js create mode 100644 Graphs/test/Kosaraju.test.js diff --git a/Graphs/Kosaraju.js b/Graphs/Kosaraju.js new file mode 100644 index 0000000000..d14b2312d6 --- /dev/null +++ b/Graphs/Kosaraju.js @@ -0,0 +1,90 @@ +/** + * Author: Adrito Mukherjee + * Kosaraju's Algorithm implementation in Javascript + * Kosaraju's Algorithm finds all the connected components in a Directed Acyclic Graph (DAG) + * It uses Stack data structure to store the Topological Sorted Order of vertices and also Graph data structure + */ + +export class Kosaraju { + constructor (graph) { + this.connections = {} + this.reverseConnections = {} + this.stronglyConnectedComponents = [] + for (const [i, j] of graph) { + this.addEdge(i, j) + } + this.topoSort() + return this.kosaraju() + } + + addNode (node) { + // Function to add a node to the graph (connection represented by set) + this.connections[node] = new Set() + this.reverseConnections[node] = new Set() + this.topoSorted = [] + } + + addEdge (node1, node2) { + // Function to add an edge (adds the node too if they are not present in the graph) + if (!(node1 in this.connections) || !(node1 in this.reverseConnections)) { + this.addNode(node1) + } + if (!(node2 in this.connections) || !(node2 in this.reverseConnections)) { + this.addNode(node2) + } + this.connections[node1].add(node2) + this.reverseConnections[node2].add(node1) + } + + dfsTopoSort (node, visited) { + visited.add(node) + for (const child of this.connections[node]) { + if (!visited.has(child)) this.dfsTopoSort(child, visited) + } + this.topoSorted.push(node) + } + + topoSort () { + // Function to perform topological sorting + const visited = new Set() + const nodes = Object.keys(this.connections).map((key) => Number(key)) + for (const node of nodes) { + if (!visited.has(node)) this.dfsTopoSort(node, visited) + } + } + + dfsKosaraju (node, visited) { + visited.add(node) + this.stronglyConnectedComponents[ + this.stronglyConnectedComponents.length - 1 + ].push(node) + for (const child of this.reverseConnections[node]) { + if (!visited.has(child)) this.dfsKosaraju(child, visited) + } + } + + kosaraju () { + // Funtion to perform Kosaraju Algorithm + const visited = new Set() + while (this.topoSorted.length > 0) { + const node = this.topoSorted.pop() + if (!visited.has(node)) { + this.stronglyConnectedComponents.push([]) + this.dfsKosaraju(node, visited) + } + } + return this.stronglyConnectedComponents + } +} + +// new Kosaraju([ +// [1, 2], +// [2, 3], +// [3, 1], +// [2, 4], +// [4, 5], +// [5, 6], +// [6, 4], +// ]) + +// [ [ 1, 3, 2 ], [ 4, 6, 5 ] ] diff --git a/Graphs/test/Kosaraju.test.js b/Graphs/test/Kosaraju.test.js new file mode 100644 index 0000000000..3cf76f949a --- /dev/null +++ b/Graphs/test/Kosaraju.test.js @@ -0,0 +1,30 @@ +import { Kosaraju } from '../Kosaraju.js' + +test('Test Case 1', () => { + const graph = [ + [1, 2], + [2, 3], + [3, 1], + [2, 4], + [4, 5], + [5, 6], + [6, 4] + ] + const stronglyConnectedComponents = new Kosaraju(graph) + expect(stronglyConnectedComponents).toStrictEqual([ + [1, 3, 2], + [4, 6, 5] + ]) +}) + +test('Test Case 2', () => { + const graph = [ + [1, 2], + [2, 3], + [3, 1], + [2, 4], + [4, 5] + ] + const stronglyConnectedComponents = new Kosaraju(graph) + expect(stronglyConnectedComponents).toStrictEqual([[1, 3, 2], [4], [5]]) +}) diff --git a/package-lock.json b/package-lock.json index aee3c01889..53a83cf06d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "standard": "^17.0.0" }, "engines": { - "node": ">=18" + "node": ">=16.6.0" } }, "node_modules/@ampproject/remapping": { From 57e97c8035ecd84cc0663ecc47c56d842d8ea7af Mon Sep 17 00:00:00 2001 From: Adrito-M Date: Wed, 19 Oct 2022 20:19:24 +0530 Subject: [PATCH 2/5] Fixes: #1214 --- Graphs/Kosaraju.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Graphs/Kosaraju.js b/Graphs/Kosaraju.js index d14b2312d6..7179221767 100644 --- a/Graphs/Kosaraju.js +++ b/Graphs/Kosaraju.js @@ -3,6 +3,9 @@ * Kosaraju's Algorithm implementation in Javascript * Kosaraju's Algorithm finds all the connected components in a Directed Acyclic Graph (DAG) * It uses Stack data structure to store the Topological Sorted Order of vertices and also Graph data structure + * + * Wikipedia: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm + * */ export class Kosaraju { From 2c25889ecfc1775b803737e3085bb69c43937b0f Mon Sep 17 00:00:00 2001 From: Adrito-M Date: Wed, 19 Oct 2022 20:22:08 +0530 Subject: [PATCH 3/5] Fixes: #1214 --- Graphs/Kosaraju.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graphs/Kosaraju.js b/Graphs/Kosaraju.js index 7179221767..24950a8750 100644 --- a/Graphs/Kosaraju.js +++ b/Graphs/Kosaraju.js @@ -67,7 +67,7 @@ export class Kosaraju { } kosaraju () { - // Funtion to perform Kosaraju Algorithm + // Function to perform Kosaraju Algorithm const visited = new Set() while (this.topoSorted.length > 0) { const node = this.topoSorted.pop() From 2754071c64055022740178c162a38fc1e7943909 Mon Sep 17 00:00:00 2001 From: Adrito-M <98008131+Adrito-M@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:27:53 +0530 Subject: [PATCH 4/5] Update package-lock.json --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 53a83cf06d..aee3c01889 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "standard": "^17.0.0" }, "engines": { - "node": ">=16.6.0" + "node": ">=18" } }, "node_modules/@ampproject/remapping": { From e6e3e2bc435fe532241a800c7f718fee1ba98f46 Mon Sep 17 00:00:00 2001 From: Adrito-M Date: Thu, 20 Oct 2022 02:05:32 +0530 Subject: [PATCH 5/5] Kosaraju.js exports function kosaraju rather than class --- Graphs/Kosaraju.js | 11 +++++++++-- Graphs/test/Kosaraju.test.js | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Graphs/Kosaraju.js b/Graphs/Kosaraju.js index 24950a8750..a0b4266b0c 100644 --- a/Graphs/Kosaraju.js +++ b/Graphs/Kosaraju.js @@ -8,7 +8,7 @@ * */ -export class Kosaraju { +class Kosaraju { constructor (graph) { this.connections = {} this.reverseConnections = {} @@ -80,7 +80,14 @@ export class Kosaraju { } } -// new Kosaraju([ +function kosaraju (graph) { + const stronglyConnectedComponents = new Kosaraju(graph) + return stronglyConnectedComponents +} + +export { kosaraju } + +// kosaraju([ // [1, 2], // [2, 3], // [3, 1], diff --git a/Graphs/test/Kosaraju.test.js b/Graphs/test/Kosaraju.test.js index 3cf76f949a..a2da394db7 100644 --- a/Graphs/test/Kosaraju.test.js +++ b/Graphs/test/Kosaraju.test.js @@ -1,4 +1,4 @@ -import { Kosaraju } from '../Kosaraju.js' +import { kosaraju } from '../Kosaraju.js' test('Test Case 1', () => { const graph = [ @@ -10,7 +10,7 @@ test('Test Case 1', () => { [5, 6], [6, 4] ] - const stronglyConnectedComponents = new Kosaraju(graph) + const stronglyConnectedComponents = kosaraju(graph) expect(stronglyConnectedComponents).toStrictEqual([ [1, 3, 2], [4, 6, 5] @@ -25,6 +25,6 @@ test('Test Case 2', () => { [2, 4], [4, 5] ] - const stronglyConnectedComponents = new Kosaraju(graph) + const stronglyConnectedComponents = kosaraju(graph) expect(stronglyConnectedComponents).toStrictEqual([[1, 3, 2], [4], [5]]) })