5

I initially had this recursive solution for a topological sort:

void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
    visited[v] = true;
    node* curr = adjList[v];

    while (curr != NULL) {
        if(!visited[curr->val]) {
            dfs(curr->val, visited, adjList, myStack);
        }
        curr = curr->next;
    }
    myStack.push(v);
}

and it seemed to work for my purposes. But I'm having trouble translating it into an iterative solution. This is my attempt:

void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
    std::stack<int> recursion;
    visited[v] = true;

    recursion.push(v);

    while( !recursion.empty() ) {
        v = recursion.top();
        recursion.pop();
        node* curr = adjList[v];

        myStack.push(v);

        while (curr != NULL) {
            if(!visited[curr->val]) {
                visited[curr->val] = true;
                recursion.push(curr->val);
            }
            curr = curr->next;
        }
    }
}

But the ordering is completely messed up! I think it might be due to the positioning of my myStack.push(v), but I don't know how to approach this. Any help would be appreciated it.

Jon
  • 359
  • 1
  • 2
  • 10
  • I mused in the past couple of days that the trick usually is, to invert the recursion exit condition and use it for the while condition of the non-recursive function. Then, I theorize, you can keep most of your old logic. – BitTickler Mar 04 '16 at 05:39
  • @BitTickler What do you mean by that? – Jon Mar 04 '16 at 05:43
  • The main difference is that in the recursion you have different states of `visited`, while in the iterative version you modify only one such list, and you unset `visited` when backtracking. – SpamBot Mar 04 '16 at 09:01

1 Answers1

3

I think I solved my own problem. Essentially, you can get the topological order by sorting the nodes by the time they finish. But instead of doing sorting and getting an O(nlogn) solution, we can keep this as O(n). When you are finished with a node, instead of recording its finish time, we can pop a unique identifier for the node onto a stack. Since we are only dealing with positive vertices in my case, it would be sufficient to make the unique identifier simply the negative of the vertex value. Thus if we pop our stack successively, we will get our topological order.

 void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
     std::stack<int> recursion;
     visited[v] = true;
     recursion.push(v);

     while( !recursion.empty() ) {
        v = recursion.top();
        recursion.pop();

        //A dummy node to denote finish order (e.g. topological order)
        if (v < 0) {
            myStack.push(v * -1);
        } else {
            node* curr = adjList[v];
            recursion.push(v * -1);

             while (curr != NULL) {
                if(!visited[curr->val]) {
                    visited[curr->val] = true;
                    recursion.push(curr->val);
                }
                curr = curr->next;
            }
        }
    }
}
Jon
  • 359
  • 1
  • 2
  • 10
  • this answer worked pretty well to me. Your sign flip trick is really smart, modulo having all entries > 0 as you mentioned, which is definitely my case. Thanks – riccardoventrella Dec 27 '21 at 08:07