Finish Tarjan algorithm and add tests

This commit is contained in:
stefiosif
2022-05-07 17:05:43 +03:00
parent 122d11b189
commit 8a52c80bc8
5 changed files with 145 additions and 117 deletions

View File

@@ -4,71 +4,80 @@
#include "graph/graph.h"
using namespace graph;
#include <stack>
#include <algorithm>
#include <iostream>
#include <ranges>
#include <iterator>
#include <algorithm>
#include <stack>
namespace algorithm {
namespace algo {
template<typename T>
class Tarjan {
public:
Tarjan(Graph<T> G) : G(G) {}
void findSCC();
//
std::vector<std::vector<T>> run();
void strongConnect(Vertex<T>& v);
std::uint16_t index = 0;
std::stack<Vertex<T>> S;
//
void strongConnect(const T& v);
private:
// Necessary info about vertices when running Tarjan's algorithm
struct Payload {
std::int16_t index = -1;
std::int16_t lowlink = -1;
bool onStack = false;
};
Graph<T> G;
std::stack<T> S;
std::int16_t index = 0;
std::map<T, Payload> vp;
std::vector<std::vector<T>> SCCs;
};
template<typename T>
void Tarjan<T>::strongConnect(Vertex<T>& v) {
v.index, v.lowlink = index++;
v.onStack = true;
inline void Tarjan<T>::strongConnect(const T& v) {
vp[v].index = vp[v].lowlink = index++;
vp[v].onStack = true;
S.push(v);
for (auto& w : v.edges) {
if (w.index == -1) {
// successor w has not yet been visited, recurse on it
for (const auto& w : G.adjMatrix[v]) {
if (vp[w].index == -1) {
strongConnect(w);
v.lowlink = std::min(v.lowlink, w.lowlink);
} else if (w.onStack) {
// successor w is in stack S and hence in the current SCC
// if w is not on stack, then (v, w) is an edge pointing to an SCC
// already found and must be ignored
v.lowlink = std::min(v.lowlink, w.index);
vp[v].lowlink = std::min(vp[v].lowlink, vp[w].lowlink);
} else if (vp[w].onStack) {
vp[v].lowlink = std::min(vp[v].lowlink, vp[w].index);
}
}
// if v is a root node, pop the stack and generate an SCC
if (v.lowlink = v.index) {
// start a new SCC
Vertex<T> w;
// If v is a root node, pop the stack and generate an SCC
if (vp[v].lowlink == vp[v].index) {
std::vector<T> SCC;
bool finished = false;
do {
w = S.top();
const auto& w = S.top();
S.pop();
// add w to current SCC
} while (w != v);
vp[w].onStack = false;
SCC.push_back(w);
finished = vp[w].index == vp[v].index;
} while (!finished);
SCCs.push_back(SCC);
}
}
template<typename T>
void Tarjan<T>::findSCC() {
inline std::vector<std::vector<T>> Tarjan<T>::run() {
for (auto& vertex : G.vertices) {
if (vertex.index == -1) {
strongConnect(vertex);
for (const auto& v : G.vertices) {
if (vp[v].index == -1) {
strongConnect(v);
}
}
return SCCs;
}
} // namespace algorithm
} // namespace algo
#endif