9

I have the following implementation of a Depth First Search algorithm:

 public static void printDFS(Node root) {
        Stack<Node> stack = new Stack<Node>();

        stack.push(root);
        while(!stack.isEmpty()) {
            Node curr = stack.pop();
            System.out.println(curr.getValue())      ;
            if (curr.getLeft() != null) {
                stack.push(curr.getLeft());
            }
            if (curr.getRight() != null) {
                stack.push(curr.getRight());
            }
        }
    }

and when I run it on a tree that looks like this:

                        0
                      /   \
                     6     7
                    / \   / \
                   5   4 3   2

I get the visited output as: 0 -> 7 -> 2 -> 3 -> 6 -> 4 -> 5

Is this a 'correct' DFS ordering? I would have expected the output to have been a pre-order traversal (ie 0 ->6 -> 5 -> 4 -> 7 -> 3 -> 2) and I know I can get this by first pushing the right node of each subtree. But what I want to know is what is the correct visitation order in a DFS algorithm?

2
  • 1
    I believe you'll get the order you expected by pushing the right node before left, thus popping off left before right when you actually process the nodes. Commented Nov 17, 2014 at 7:03
  • 5
    Both are correct visitation orders of DFS Commented Nov 17, 2014 at 7:05

5 Answers 5

6

As already mentioned in another answer the reason why your visitation -> traversal order is "inversed" lies in the fact that you are using a Stack to keep track of the "current node".

Let me walk you through your example tree:

                    0 
                  /   \
                 6     7
                / \   / \
               5   4 3   2

stack.push(root) leads to following stack state:

0: 0 <-- (root) and Top of stack

You're popping the stack and put it in curr. In traversal terms you are now in this state:

                    0 <--
                  /   \
                 6     7
                / \   / \
               5   4 3   2

you then proceed to add curr.getLeft() to the stack and then curr.getRight(). This leads to following stack state:

1: 7 <--(curr.getRight()) <-- Top of stack
0: 6 <--(curr.getLeft())

Repeating the same step we get following traversal state:

                    0 
                  /   \
                 6     7<--
                / \   / \
               5   4 3   2

and after adding the nodes:

2: 2 <-- Top of stack
1: 3
0: 6 <-- (initial getLeft())

as both nodes have no children, popping them from the stack and outputting them gets us to following traversal state:

                    0 
                  /   \
              -->6     7
                / \   / \
               5   4 3   2

The rest of this is history ;)

As you specificially asked about a "correct" way (or ordering) for a DFS: There is none. You define what side you traverse to depth first.

Sign up to request clarification or add additional context in comments.

Comments

2

It's a stack. What you push last will pop first

1 Comment

While this is the correct cause for the difference between expected and actual output it would probably be helpful to OP if you could explain a little more...p
2

There is no such "correct DFS ordering". The main idea of DFS is to go deep; visiting children before siblings for any given node. Once you go far deep in the graph and you encounter a leaf, you backtrack and examine the nearest sibling in the same way.

The way you choose which child to examine first result in different traversing orders (or trees). Needless to say, all traversing methods result in a spanning tree over the graph. Pre-order traversing, the one you are comparing with, is probably the most well known order for DFS (or at least this is what I have seen). Others are valid but not too popular.

Comments

1

Here is a pseudo code for DFS:

''' This is much more of a traversal algorithm than search. '''

Algorithm DFS(Tree):
     initialize stack to contain Tree.root()
     while stack is not empty:
         p = stack.pop()
         perform 'action' for p
         for each child 'c' in Tree.children(p):
             stack.push(c)

This will search through all the nodes of tree whether binary or not. To implement search and return.. modify the algorithm accordingly.

Comments

-3

There are a few options to consider for your DFS algorithm:

  1. Firstly, use Backtracking algorithm to do a DFS search.
  2. If using Backtracking add only leftChild while traversing downwards. Otherwise reverse the order in which you push() node's children onto the Stack i.e rightChild right and then leftChild.
  3. Again if using Backtracking, avoid cycles by creating a variable nodeVistited which will be set to true once a node has been pushed on stack. Not needed otherwise. Try with these changes or let me know I will post code for DFS.

6 Comments

The example traversals and their outputs from the wikipedia article on DFS contradict your first point. You're hanging yourself up on minor implementation details. Additionally your second point is blatantly incorrect and the third point is irrelevant. Already visited nodes are tracked in the stack. In a clean tree (as it is assumed) no nodes will be revisited
@Vogel612 For point 1. I would say DFS is a Backtracking algorithm and hence its algorithm should be based on the same. Which maintains a stack of all nodes from root to leaf node. As for Point 2. In order to achieve the traversal order mentioned by user he has two options. First I already mentioned i.e to add only leftChild while traversing down the tree. Second option is to reverse the order of pushing leftChild and rightChild onto the stack i.e rightChild first and then leftChild. Point 3. is optional as per design. My answer is as per question asked not as per wikipedia.
Backtracking does not require to maintain all nodes from root to leaf, just those that were not "completed" yet. OP's code already accomplishes that, and the point you are making in 1. does not address that in any way. concerning 2.: "at the same time" is incorrect. one after another is not at the same time. Also DFS or BFS only depends on how you handle stuff. It would be easy to switch this from a DFS to a BFS traversal by changing the Stack to a Queue. While your answer relates to the question it's .. wrong ;)
@Vogel612 without all the elements from root to leaf node, backtracking to root is not possible. at the same time means a traversal step not in the context of time. thought you be smart enough to understand that ;).
The 'Backtracking' you describe is an implementation detail. A DFS does not require Backtracking for correct execution, this means your initial assumption is "incorrect". There is no necessity to backtrack to root for a DFS. I would say "at the same time" is pretty... unambiguous, I'd probably not have criticised "in the same traversal step". I would be interested in how you'd solve the problem without somewhen adding both children of a Node to the backtracking queue ;) Btw, feel free to join me in Stack Overflow Chat for a discussion. You can find me in the Java room
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.