Go to the source code of this file.
Classes | |
| struct | SccCounterOutput< NodeIndex > |
| A simple custom output class that just counts the number of SCC. More... | |
Functions | |
| template<typename NodeIndex , typename Graph , typename SccOutput > | |
| void | FindStronglyConnectedComponents (const NodeIndex num_nodes, const Graph &graph, SccOutput *components) |
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. More... | |
| void FindStronglyConnectedComponents | ( | const NodeIndex | num_nodes, |
| const Graph & | graph, | ||
| SccOutput * | components | ||
| ) |
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
This implementation is slightly different than a classical iterative version of Tarjan's strongly connected components algorithm.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This code computes the strongly connected components of a directed graph, and presents them sorted by reverse topological order.
It implements an efficient version of Tarjan's strongly connected components algorithm published in: Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing.
A description can also be found here: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
SIMPLE EXAMPLE:
Fill a std::vector<std::vector<int>> graph; representing your graph adjacency lists. That is, graph[i] contains the nodes adjacent to node #i. The nodes must be integers in [0, num_nodes). Then just do:
std::vector<std::vector<int>> components; FindStronglyConnectedComponents( static_cast<int>(graph.size()), graph, &components);
The nodes of each strongly connected components will be listed in each subvector of components. The components appear in reverse topological order: outgoing arcs from a component will only be towards earlier components.
IMPORTANT: num_nodes will be the number of nodes of the graph. Its type is the type used internally by the algorithm. It is why it is better to convert it to int or even int32 rather than using size_t which takes 64 bits. Finds the strongly connected components of a directed graph. It is templated so it can be used in many contexts. See the simple example above for the easiest use case.
The requirement of the different types are:
More practical details on the algorithm:
Its memory usage is also bounded by O(nodes + edges) but in practice it uses less than the input graph.
But basically it is still an iterative DFS.
Each node expanded by the DFS will be pushed on this stack. A node is only popped back when its strongly connected component has been explored and outputted.
This is equivalent to the "low link" of a node in Tarjan's algorithm. Basically, scc_start_index.back() represent the 1-based index in scc_stack of the beginning of the current strongly connected component. All the nodes after this index will be on the same component.
Optimization. This will always be equal to scc_start_index.back() except when scc_stack is empty, in which case its value does not matter.
Each node is assigned an index which changes 2 times in the algorithm:
This is a well known way to do an efficient iterative DFS. Each time a node is explored, all its adjacent nodes are pushed on this stack. The iterative dfs processes the nodes one by one by popping them back from here.
Loop over all the nodes not yet settled and start a DFS from each of them.
We continue the dfs from this node and set its 1-based index.
Enqueue all its adjacent nodes.
Update the start of this strongly connected component.
We found a strongly connected component.
Definition at line 105 of file strongly_connected_components.h.