Skip to content

Commit

Permalink
Issue 211 (Add Kosaraju Algorithm) (#219)
Browse files Browse the repository at this point in the history
* Update Graph.hpp

* Update Graph.hpp

Made the requested changes.
Corrected the commenting.
Moved the Doxygen documentation before the function declaration and corrected the documentation of the other function that I messed up earlier.
  • Loading branch information
sarthak17jain authored Oct 3, 2022
1 parent f5938c3 commit 1235fd0
Showing 1 changed file with 109 additions and 0 deletions.
109 changes: 109 additions & 0 deletions include/Graph/Graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <list>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <cstring>
#include <functional>
Expand Down Expand Up @@ -339,6 +340,18 @@ namespace CXXGRAPH
*/
virtual bool isStronglyConnectedGraph() const;

/**
* \brief
* This function performs performs the kosaraju algorthm on the graph to find the strongly connected components.
*
* Mathematical definition of the problem:
* A strongly connected component (SCC) of a directed graph is a maximal strongly connected subgraph.
* Note: No Thread Safe
* @return a vector of vector of strongly connected components.
*/
virtual std::vector<std::vector<Node<T>>> kosaraju() const;

/**
* \brief
* This function performs Graph Slicing based on connectivity
Expand Down Expand Up @@ -1948,6 +1961,102 @@ namespace CXXGRAPH
}
}

template <typename T>
std::vector<std::vector<Node<T>>> Graph<T>::kosaraju() const
{
std::vector<std::vector<Node<T>>> connectedComps;

if (!isDirectedGraph())
{
return connectedComps;//empty vector since for undirected graph strongly connected components do not exist
}
else
{
auto nodeSet = getNodeSet();
auto adjMatrix = getAdjMatrix();
// created visited map
std::unordered_map<unsigned long, bool> visited;
for (const auto &node : nodeSet)
{
visited[node->getId()] = false;
}

std::stack<const Node<T> *> st;
std::function<void(const Node<T> *)> dfs_helper = [this, &adjMatrix, &visited, &dfs_helper, &st](const Node<T> *source)
{
// mark the vertex visited
visited[source->getId()] = true;

// travel the neighbors
for (int i = 0; i < adjMatrix[source].size(); i++)
{
const Node<T> *neighbor = adjMatrix[source].at(i).first;
if (visited[neighbor->getId()] == false)
{
// make recursive call from neighbor
dfs_helper(neighbor);
}
}

st.push(source);
};

for (const auto &node : nodeSet)
{
if (visited[node->getId()] == false)
{
dfs_helper(node);
}
}

//construct the transpose of the given graph
AdjacencyMatrix<T> rev;
auto addElementToAdjMatrix = [&rev](const Node<T> *nodeFrom, const Node<T> *nodeTo, const Edge<T> *edge){
std::pair<const Node<T> *, const Edge<T> *> elem = {nodeTo, edge};
rev[nodeFrom].push_back(std::move(elem));
};
for (const auto &edgeSetIt : edgeSet)
{
const DirectedEdge<T> *d_edge = dynamic_cast<const DirectedEdge<T> *>(edgeSetIt);
//Add the reverse edge to the reverse adjacency matrix
addElementToAdjMatrix(&(d_edge->getTo()), &(d_edge->getFrom()), d_edge);
}

visited.clear();

std::function<void(const Node<T> *, std::vector<Node<T>> &)> dfs_helper1 = [this, &rev, &visited, &dfs_helper1](const Node<T> *source, std::vector<Node<T>> &comp)
{
// mark the vertex visited
visited[source->getId()] = true;
//Add the current vertex to the strongly connected component
comp.push_back(*source);

// travel the neighbors
for (int i = 0; i < rev[source].size(); i++)
{
const Node<T> *neighbor = rev[source].at(i).first;
if (visited[neighbor->getId()] == false)
{
// make recursive call from neighbor
dfs_helper1(neighbor, comp);
}
}
};

while(st.size()!=0){
auto rem = st.top();
st.pop();
if(visited[rem->getId()] == false){
std::vector<Node<T>> comp;
dfs_helper1(rem, comp);
connectedComps.push_back(comp);
}
}

return connectedComps;
}
}

template <typename T>
const DialResult Graph<T>::dial(const Node<T> &source, int maxWeight) const
{
Expand Down

0 comments on commit 1235fd0

Please sign in to comment.