Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 211 (Add Kosaraju Algorithm) #219

Merged
merged 2 commits into from
Oct 3, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 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 @@ -355,6 +356,19 @@ namespace CXXGRAPH
* @param start Node from where traversing starts
* @return a vector of nodes that belong to C but not to M.
*/

virtual std::vector<std::vector<Node<T>>> kosaraju() const;
/**
sarthak17jain marked this conversation as resolved.
Show resolved Hide resolved
* \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 const std::vector<Node<T>> graph_slicing(const Node<T> &start) const;

/**
Expand Down Expand Up @@ -1948,6 +1962,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