Finish Tarjan algorithm and add tests
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user