I donโt know if this is the best solution, but you can create a list of ready times using only the stack and the visited array of states, having more than one visit state.
The following code is for illustrative purposes only. I didnโt actually test it (just a small {{0, {1}}, {1, <>}, {2, <>}} small test), but I already used this technique the same way as before, for large graphs, and I know this works.
The idea is to keep the visited node on the stack after it is visited until everyone is visited before it pops, thus emulating a recursive call, but with less data being pushed on the stack as well.
#include <iostream> #include <vector> #include <stack> #include <cassert> #include <unordered_map> using namespace std; typedef enum { vssClean, vssPushed, vssVisited } VerticeStackState; typedef unordered_map <int, vector<int>> graph; void kosarajuBuildFinishOrder(const int inital, graph &G, vector<int> &finish, vector<VerticeStackState> &state, int &lastFinished) { assert(vssClean == state[inital]); std::stack<int> stack; stack.push(inital); state[inital] = vssPushed; int current; while (!stack.empty()) { current = stack.top(); if (vssPushed == state[current]) { state[current] = vssVisited; for (const auto to: G[current]) { if (state[to]==vssClean) { state[to] = vssPushed; stack.push(to); } } } else { assert(vssVisited == state[current]); stack.pop(); finish[--lastFinished] = current; } } } int main() { graph G; G.insert({0, vector<int>(1, 1)}); G.insert({1, vector<int>()}); G.insert({2, vector<int>()}); vector<int> finish(G.size(), 0); vector <VerticeStackState> state(G.size(), vssClean); int lastFinished = G.size(); for (int i=0; i < G.size(); ++i) { if (vssClean == state[i]){ kosarajuBuildFinishOrder(i, G, finish, state, lastFinished); } } for (auto i: finish) { cout << i << " "; } return 0; }
source share