-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
483 additions
and
0 deletions.
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
8 changes: 8 additions & 0 deletions
8
docs/docs/algorithms/strongly-connected-components/_category_.json
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,8 @@ | ||
{ | ||
"label": "Strongly Connected Component Algorithms", | ||
"position": 4, | ||
"link": { | ||
"type": "generated-index" | ||
} | ||
} | ||
|
22 changes: 22 additions & 0 deletions
22
docs/docs/algorithms/strongly-connected-components/tarjan.md
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,22 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Tarjan's Strongly Connected Components | ||
|
||
Tarjan's algorithm computes the Strongly Connected Components (SCCs) of a directed graph. An SCC is a subset of vertices in the graph for which every vertex is reachable from every other vertex in the subset, i.e. there exists a path between all pairs of vertices for the subset of vertices. | ||
|
||
Tarjan's algorithm runs in `O(|V| + |E|)` for directed graphs, where `|V|` the number of vertices and `|E|` is the number of edges in the graph. So it runs in linear time. | ||
|
||
[wikipedia](https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) | ||
|
||
## Syntax | ||
|
||
```cpp | ||
template <typename V, typename E> | ||
[[nodiscard]] std::vector<std::vector<vertex_id_t>> | ||
tarjans_strongly_connected_components(const graph<V, E, graph_type::DIRECTED>& graph); | ||
``` | ||
- **graph** The graph for which to compute SCCs. | ||
- **return** A vector of vectors representing SCCs. |
30 changes: 30 additions & 0 deletions
30
include/graaflib/algorithm/strongly_connected_components.h
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,30 @@ | ||
#pragma once | ||
|
||
#include <graaflib/graph.h> | ||
#include <graaflib/types.h> | ||
|
||
namespace graaf::algorithm { | ||
|
||
/** | ||
* Computes the Strongly Connected Components (SCCs) of a graph using Tarjan's | ||
* algorithm. | ||
* | ||
* This function takes a graph and returns a vector of vectors representing the | ||
* SCCs. Each inner vector contains the vertices of a strongly connected | ||
* component, and the outer vector contains all the strongly connected | ||
* components in the graph. | ||
* | ||
* @tparam V Vertex type. | ||
* @tparam E Edge type. | ||
* @param graph The graph for which to compute SCCs. | ||
* @return std::vector<std::vector<vertex_id_t>> A vector of vectors | ||
* representing SCCs. | ||
*/ | ||
template <typename V, typename E> | ||
[[nodiscard]] std::vector<std::vector<vertex_id_t>> | ||
tarjans_strongly_connected_components( | ||
const graph<V, E, graph_type::DIRECTED>& graph); | ||
|
||
} // namespace graaf::algorithm | ||
|
||
#include "strongly_connected_components.tpp" |
82 changes: 82 additions & 0 deletions
82
include/graaflib/algorithm/strongly_connected_components.tpp
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,82 @@ | ||
#pragma once | ||
|
||
#include <graaflib/algorithm/strongly_connected_components.h> | ||
|
||
#include <functional> // For std::function | ||
#include <stack> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
namespace graaf::algorithm { | ||
|
||
template <typename V, typename E> | ||
[[nodiscard]] std::vector<std::vector<vertex_id_t>> | ||
tarjans_strongly_connected_components( | ||
const graph<V, E, graph_type::DIRECTED>& graph) { | ||
// Vector to store strongly connected components | ||
std::vector<std::vector<vertex_id_t>> sccs; | ||
|
||
// Stack to hold vertices during traversal | ||
std::stack<vertex_id_t> stack; | ||
|
||
// Maps to keep track of indices, low-link values, and stack membership | ||
std::unordered_map<vertex_id_t, size_t> indices; | ||
std::unordered_map<vertex_id_t, size_t> low_links; | ||
std::unordered_map<vertex_id_t, bool> on_stack; | ||
|
||
// Counter for indexing vertices | ||
size_t index_counter = 0; | ||
|
||
// Lambda function for the strong connect traversal | ||
std::function<void(vertex_id_t)> strong_connect; | ||
|
||
strong_connect = [&](vertex_id_t vertex) { | ||
// Set indices and low-link values for the current vertex | ||
indices[vertex] = index_counter; | ||
low_links[vertex] = index_counter; | ||
index_counter++; | ||
|
||
// Push the vertex onto the stack and mark it as on-stack | ||
stack.push(vertex); | ||
on_stack[vertex] = true; | ||
|
||
// Traverse neighbors | ||
for (const auto neighbor : graph.get_neighbors(vertex)) { | ||
if (!indices.contains(neighbor)) { | ||
// Neighbor has not yet been visited; recurse on it | ||
strong_connect(neighbor); | ||
low_links[vertex] = std::min(low_links[vertex], low_links[neighbor]); | ||
} else if (on_stack[neighbor]) { | ||
// Neighbor is in stack and hence in the current SCC | ||
low_links[vertex] = std::min(low_links[vertex], indices[neighbor]); | ||
} | ||
} | ||
|
||
// If low-link and index match, a strongly connected component is found | ||
if (low_links[vertex] == indices[vertex]) { | ||
std::vector<vertex_id_t> scc; | ||
vertex_id_t top; | ||
// Pop vertices from the stack to form the SCC | ||
do { | ||
top = stack.top(); | ||
stack.pop(); | ||
on_stack[top] = false; | ||
scc.push_back(top); // Add to current strongly connected component | ||
} while (top != vertex); | ||
|
||
// Add the SCC to the list of SCCs | ||
sccs.push_back(scc); | ||
} | ||
}; | ||
|
||
// Traverse all vertices to find SCCs | ||
for (const auto& [vertex_id, vertex] : graph.get_vertices()) { | ||
if (!indices.contains(vertex_id)) { | ||
strong_connect(vertex_id); | ||
} | ||
} | ||
|
||
return sccs; | ||
} | ||
|
||
} // namespace graaf::algorithm |
Oops, something went wrong.