Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterative DFS vs Recursive DFS and different elements order

I have written a recursive DFS algorithm to traverse a graph:

void Graph<E, N>::DFS(Node n)
{
    std::cout << ReadNode(n) << " ";

    MarkVisited(n);

    NodeList adjnodes = Adjacent(n);

    NodeList::position pos = adjnodes.FirstPosition();

    while(!adjnodes.End(pos))
    {
        Node adj = adjnodes.ReadList(pos);

        if(!IsMarked(adj))
            DFS(adj);

        pos = adjnodes.NextPosition(pos);
    }
}

Then I have written an iterative DFS algorithm using a stack:

template <typename E, typename N>
void Graph<E, N>::IterativeDFS(Node n)
{
    Stack<Node> stack;

    stack.Push(n);

    while(!stack.IsEmpty())
    {
        Node u = stack.Read();

        stack.Pop();

        if(!IsMarked(u))
        {
            std::cout << ReadNode(u) << " ";

            MarkVisited(u);

            NodeList adjnodes = Adjacent(u);

            NodeList::position pos = adjnodes.FirstPosition();

            while(!adjnodes.End(pos))
            {
                stack.Push(adjnodes.ReadList(pos));

                pos = adjnodes.NextPosition(pos);
            }
        }
    }

My problem is that in a graph in which, for example, I enter the three nodes 'a', 'b', 'c' with arcs ('a', 'b') and ('a', 'c') my output is:

'a', 'b', 'c' with the recursive DFS version, and:

'a', 'c', 'b' with the iterative DFS one.

How could I get the same order? Am I doing something wrong?

Thank you!

like image 413
JohnQ Avatar asked Feb 08 '12 20:02

JohnQ


People also ask

Is recursive DFS faster than iterative DFS?

They both work fine on files with small sizes (less than 1 MB). However, when I try to run them over files with 50 MB, it seems like that the recursive-DFS (9 secs) is much faster than that using an iterative approach (at least several minutes). In fact, the iterative approach took ages to finish.

Is DFS iterative or recursive?

The only difference between iterative DFS and recursive DFS is that the recursive stack is replaced by a stack of nodes. Algorithm: Created a stack of nodes and visited array.

What is the difference between DFS and recursion?

@ChristianLeon DFS means that you move from an element to its element. Recursion means that you define something through this itself.

In what order does depth first search explore the nodes in a graph?

a depth-first search starting at the node A, assuming that the left edges in the shown graph are chosen before right edges, and assuming the search remembers previously visited nodes and will not repeat them (since this is a small graph), will visit the nodes in the following order: A, B, D, F, E, C, G.


3 Answers

Both are valid DFS algorithms. A DFS does not specify which node you see first. It is not important because the order between edges is not defined [remember: edges are a set usually]. The difference is due to the way you handle each node's children.

In the iterative approach: You first insert all the elements into the stack - and then handle the head of the stack [which is the last node inserted] - thus the first node you handle is the last child.

In the recursive approach: You handle each node when you see it. Thus the first node you handle is the first child.

To make the iterative DFS yield the same result as the recursive one - you need to add elements to the stack in reverse order [for each node, insert its last child first and its first child last]

like image 135
amit Avatar answered Oct 04 '22 07:10

amit


The most obvious diff is the order you utilize the children.

In the Recursive method: You take the first child and run with it as soon as it comes

while in iterative approach: You push all the children in the stack and then take the top of the stack i.e the last child

To produce the same result just do the insertion of children in reverse order.

The other diff would be memory usage as one would use call stack while the other would use a stack that you make or one the STL elements:

You can read about this here: https://codeforces.com/blog/entry/17307

like image 27
ASHUTOSH SINGH Avatar answered Oct 01 '22 07:10

ASHUTOSH SINGH


Here I leave my solution recursively, very fast to implement. It is only a matter of adjusting it for any problem that requires the use of this algorithm.

It is very important to mark the current state as visited, defined as ok[u] = true, even having all the states as they have not been visited using memset(ok, 0, sizeof ok)

#define forn(i , a , b) for(int i=(a);i<(b);i++)

vector<int> arr[10001];
bool ok[10001];

void addE(int u , int v){
  arr[u].push_back(v);
  arr[v].push_back(u);
}

void dfs(int u){
  ok[u] = true;
  forn(v , 0 , (int)arr[u].size()) if(!ok[arr[u][v]]) dfs(arr[u][v]);
}

int main(){
  //...
  memset(ok , 0 , sizeof ok);
  //... 
  return 0;
}
like image 30
Chris Michael Avatar answered Oct 03 '22 07:10

Chris Michael