-
Notifications
You must be signed in to change notification settings - Fork 412
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added reverseGraph method to Graph (and its test) * Added Strongly Connected Component Algorithm (and its test) * Fix code style problems * Fix code style problems * Fix code style problems * Improved documentation * Use addEdge method instead of hard coding * Use stack more properly * Move function creation out of loop * Fix style problem
- Loading branch information
Showing
5 changed files
with
199 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
'use strict'; | ||
|
||
var Stack = require('../../data_structures/stack'); | ||
var depthFirstSearch = require('../../algorithms/graph/depth_first_search'); | ||
|
||
/** | ||
* Kosaraju's Strongly Connected Component algorithm, https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm | ||
* Complexity: O(V + E). | ||
* | ||
* @param {Graph} graph | ||
* @return {{count: number, id: Object.<string, number>}} | ||
* count is the number of strongly connected components in the graph | ||
* id is a Object, receives a vertex and returns id of the strongly | ||
* connected component vertex belongs to, ranges from 0 to count - 1. | ||
* note: 1.if v and w are in same scc, then id[v] == id[w] | ||
* 2.if v and w are in different scc and there is a path from v to w, then id[v] > id[w]. | ||
* | ||
* Usage: | ||
* var scc = stronglyConnectedComponent(g); | ||
* scc.count; // count of strongly connected components | ||
* scc.id[v]; // id of the strongly connected component which v belongs to | ||
*/ | ||
var stronglyConnectedComponent = function(graph) { | ||
var reverse = graph.reverse(); | ||
var stack = new Stack(); | ||
var visited = {}; | ||
var count = 0; | ||
var id = Object.create(null); | ||
|
||
reverse.vertices.forEach(function(node) { | ||
if (!visited[node]) { | ||
depthFirstSearch(reverse, node, { | ||
allowTraversal: function(node, neighbor) { | ||
return !visited[neighbor]; | ||
}, | ||
enterVertex: function(node) { | ||
visited[node] = true; | ||
}, | ||
leaveVertex: function(node) { | ||
stack.push(node); | ||
} | ||
}); | ||
} | ||
}); | ||
|
||
visited = {}; | ||
var allowTraversal = function(node, neighbor) { | ||
return !visited[neighbor]; | ||
}; | ||
var enterVertex = function(node) { | ||
visited[node] = true; | ||
id[node] = count; | ||
}; | ||
|
||
while (!stack.isEmpty()) { | ||
var node = stack.pop(); | ||
if (!visited[node]) { | ||
depthFirstSearch(graph, node, { | ||
allowTraversal: allowTraversal, | ||
enterVertex: enterVertex | ||
}); | ||
++count; | ||
} | ||
} | ||
|
||
return { | ||
count: count, | ||
id: id | ||
}; | ||
}; | ||
|
||
module.exports = stronglyConnectedComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
'use strict'; | ||
|
||
var root = require('../../../'); | ||
var Graph = root.DataStructures.Graph; | ||
var stronglyConnectedComponent = root.Graph.strongConnectedComponent; | ||
var assert = require('assert'); | ||
|
||
describe('Strongly Connected Component', function() { | ||
it('should correctly compute strongly connected components', function() { | ||
// graph: 0 -> 1 -> 2 | ||
var graph = new Graph(); | ||
graph.addEdge(0, 1); | ||
graph.addEdge(1, 2); | ||
|
||
var scc = stronglyConnectedComponent(graph); | ||
assert.equal(scc.count, 3); | ||
assert(scc.id[0] > scc.id[1]); | ||
assert(scc.id[1] > scc.id[2]); | ||
|
||
// graph: 0 <-> 1 -> 2 | ||
graph = new Graph(); | ||
graph.addEdge(0, 1); | ||
graph.addEdge(1, 0); | ||
graph.addEdge(1, 2); | ||
|
||
scc = stronglyConnectedComponent(graph); | ||
assert.equal(scc.count, 2); | ||
assert.equal(scc.id[0], scc.id[1]); | ||
assert(scc.id[1] > scc.id[2]); | ||
|
||
// graph: http://algs4.cs.princeton.edu/42digraph/images/transitive-closure.png | ||
graph = new Graph(); | ||
graph.addEdge(0, 1); | ||
graph.addEdge(0, 5); | ||
graph.addEdge(2, 0); | ||
graph.addEdge(2, 3); | ||
graph.addEdge(3, 2); | ||
graph.addEdge(3, 5); | ||
graph.addEdge(4, 2); | ||
graph.addEdge(4, 3); | ||
graph.addEdge(5, 4); | ||
graph.addEdge(6, 0); | ||
graph.addEdge(6, 4); | ||
graph.addEdge(6, 9); | ||
graph.addEdge(7, 6); | ||
graph.addEdge(7, 8); | ||
graph.addEdge(8, 7); | ||
graph.addEdge(8, 9); | ||
graph.addEdge(9, 10); | ||
graph.addEdge(9, 11); | ||
graph.addEdge(10, 12); | ||
graph.addEdge(11, 4); | ||
graph.addEdge(11, 12); | ||
graph.addEdge(12, 9); | ||
|
||
scc = stronglyConnectedComponent(graph); | ||
assert.equal(scc.count, 5); | ||
|
||
// scc no.0 | ||
assert(scc.id[0] > scc.id[1]); | ||
|
||
// scc no.1 | ||
assert.equal(scc.id[0], scc.id[2]); | ||
assert.equal(scc.id[0], scc.id[3]); | ||
assert.equal(scc.id[0], scc.id[4]); | ||
assert.equal(scc.id[0], scc.id[5]); | ||
|
||
// scc no.2 | ||
assert(scc.id[9] > scc.id[0]); | ||
assert.equal(scc.id[9], scc.id[10]); | ||
assert.equal(scc.id[9], scc.id[11]); | ||
assert.equal(scc.id[9], scc.id[12]); | ||
|
||
// scc no.3 | ||
assert(scc.id[6] > scc.id[9]); | ||
|
||
// scc no.4 | ||
assert(scc.id[7] > scc.id[6]); | ||
assert.equal(scc.id[7], scc.id[8]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters