// // C++ implementation of Tarjan's strongly connected components algorithm // See https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm // #include #include #include #include #include struct noncopyable { noncopyable() {} noncopyable(const noncopyable&) = delete; noncopyable& operator=(const noncopyable&) = delete; }; template class tarjan; template class vertex : private noncopyable { public: explicit vertex(const T& t) : data_(t) {} void add_neighbour(vertex* v) { neighbours_.push_back(v); } void add_neighbours(const std::initializer_list& vs) { neighbours_.insert(neighbours_.end(), vs); } const T& get_data() { return data_; } private: friend tarjan; T data_; int index_ = -1; int lowlink_ = -1; bool on_stack_ = false; std::vector neighbours_; }; template class graph : private noncopyable { public: vertex* add_vertex(const T& t) { vertexes_.emplace_back(t); return &vertexes_.back(); } private: friend tarjan; std::list> vertexes_; }; template class tarjan : private noncopyable { public: using component = std::vector*>; std::list run(graph& graph) { index_ = 0; stack_.clear(); strongly_connected_.clear(); for (auto& v : graph.vertexes_) { if (v.index_ == -1) strongconnect(&v); } return strongly_connected_; } private: void strongconnect(vertex* v) { v->index_ = index_; v->lowlink_ = index_; ++index_; stack_.push_back(v); v->on_stack_ = true; for (auto w : v->neighbours_) { if (w->index_ == -1) { strongconnect(w); v->lowlink_ = std::min(v->lowlink_, w->lowlink_); } else if (w->on_stack_) { v->lowlink_ = std::min(v->lowlink_, w->index_); } } if (v->lowlink_ == v->index_) { strongly_connected_.push_back(component()); component& c = strongly_connected_.back(); for (;;) { auto w = stack_.back(); stack_.pop_back(); w->on_stack_ = false; c.push_back(w); if (w == v) break; } } } int index_ = 0; std::list*> stack_; std::list strongly_connected_; }; template void print_vector(const std::vector*>& vec) { if (!vec.empty()) { auto i = vec.begin(); std::cout << (*i)->get_data(); for (++i; i != vec.end(); ++i) std::cout << ' ' << (*i)->get_data(); } std::cout << '\n'; } int main() { graph g; auto andy = g.add_vertex("Andy"); auto bart = g.add_vertex("Bart"); auto carl = g.add_vertex("Carl"); auto dave = g.add_vertex("Dave"); auto earl = g.add_vertex("Earl"); auto fred = g.add_vertex("Fred"); auto gary = g.add_vertex("Gary"); auto hank = g.add_vertex("Hank"); andy->add_neighbour(bart); bart->add_neighbour(carl); carl->add_neighbour(andy); dave->add_neighbours({bart, carl, earl}); earl->add_neighbours({dave, fred}); fred->add_neighbours({carl, gary}); gary->add_neighbour(fred); hank->add_neighbours({earl, gary, hank}); tarjan t; for (auto&& s : t.run(g)) print_vector(s); return 0; }