Talk:Tree traversal

From Wikipedia, the free encyclopedia
Jump to: navigation, search
WikiProject Java (Rated C-class, Low-importance)
WikiProject icon This article is within the scope of WikiProject Java, a collaborative effort to improve the coverage of Java on Wikipedia. If you would like to participate, please visit the project page, where you can join the discussion and see a list of open tasks.
C-Class article C  This article has been rated as C-Class on the project's quality scale.
 Low  This article has been rated as Low-importance on the project's importance scale.
 
Note icon
This article has been automatically rated by a bot or other tool because one or more other projects use this class. Please ensure the assessment is correct before removing the |auto= parameter.
WikiProject Computer science (Rated C-class, High-importance)
WikiProject icon This article is within the scope of WikiProject Computer science, a collaborative effort to improve the coverage of Computer science related articles on Wikipedia. If you would like to participate, please visit the project page, where you can join the discussion and see a list of open tasks.
C-Class article C  This article has been rated as C-Class on the project's quality scale.
 High  This article has been rated as High-importance on the project's importance scale.
 

Iterative Inorder Traversal[edit]

Algorithm requires a check if a node has been already printed other wise it will always keep on printing the leftmost and its parent. —Preceding unsigned comment added by 66.235.10.126 (talkcontribs) 30 December 2005

Thanks! When doing the recursive to iterative translation I forgot to keep in mind that we somehow have to remember the code position at the last call. I'll ponder how to do this in a neat clean way. Deco 10:59, 30 December 2005 (UTC)

This is what I came up with in C/C++

   void inorder(node* root) {
     bool done = false;
     Stack<node*> stack;
     node* current = root;
     while (!done)
     {
       if (current)
       {
           stack.push(current);
           current = current->left;
        }
       else
       {
            if ( stack.empty() == false)
            {
              current = stack.pop();
              cout << current->value;
              current = current->right;
             }
             else 
                   done = true;
       }
     }
   }

—Preceding unsigned comment added by 131.107.0.106 (talkcontribs) 31 December 2005

Iterative Traversal Redux[edit]

The currently presented iterative algorithm I find a little too obscure. For reference, here it is:

visit(root) {
    prev    := null
    current := root
    next    := null
   
    while current ≠ null {
        if prev == current.parent
            prev := current
            next := current.left
        if next == null or prev == current.left
            print current.value
            prev := current
            next := current.right
        if next == null or prev == current.right
            prev := current
            next := current.parent
        current := next
    }
}

For a few days, the following version was in the article:

visit(root) {
    prev    := null
    current := root
    next    := null
   
    while current ≠ null {
        if prev == current.parent
            next := current.left
        if next == null or prev == current.left
            print current.value
            next := current.right
        if next == null or prev == current.right
            next := current.parent
        prev := current
        current := next
    }
}

It's a little simpler because the "prev := current" has been factored out. But it doesn't work in some cases because of subtleties in the code. It's not a simple factoring because in the original the "prev := current" affected the if statements which followed it, which the factored version does not. Only occasionally does that matter.

One case it fails for is where the root has only one child, a left-hand child. After taking the first then clause ("next := current.left") it mistakenly executes the third then clause ("next := current.parent") causing next to be set to null and the loop to be exited. This is because the test "prev == current.right" succeeds since both values are null. In the original/current code, this failure was prevented by the earlier execution of "prev := current".

I think the current algorithm is too subtle to be a good example. I'm looking at modifications to clarify it. -R. S. Shaw 03:27, 9 June 2006 (UTC)

Ah, I see. I didn't take into account the fact that the flow of execution fell through to the next if statement. Al 03:44, 9 June 2006 (UTC)
I agree. I wrote it. If you can come up with anything simpler that would be great. Deco 09:10, 9 June 2006 (UTC)
After looking at some alternatives, I've put in a new version of the algorithm. This one uses a nested subroutine (for something that could have just been duplicate code) because it seemed a little clearer despite the extra routine. -R. S. Shaw 00:17, 10 June 2006 (UTC)
Personally I find that more complicated, since "midvisit" doesn't seem to have a clear conceptual role. Maybe I'm missing something. Deco 01:20, 10 June 2006 (UTC)

Flaws in All These Algorithms[edit]

I notice that all of the algorithms that I looked at on this page contain at least one major bug: They will fail if they are initially passed an empty tree. There is a better way to write them, that avoids this bug (or obligation on the caller if you prefer) and is just as efficient. For example, the preorder traversal could be written (using the same style):

 visit(node)
     if (node == null) return
     print node.value
     visit(node.left)
     visit(node.right)

While this makes twice as many calls to "visit", it also avoids half the dereferences to node's children, so that's arguably a performance wash (it depends on the circumstances as to which will truly run faster). And it eliminates the major bug. All of these code examples can and should be rewritten in the same way.

I think it would also be clearer to call the functions "preorder" "postorder" and "inorder," respectively, instead of calling them all "visit." Cliff Shaffer, 10:25, 21 September 2006.

Rewrite[edit]

I rewrote the article, removing implementations, as they were probably incorrect, according to the various comments on them, and as implementations don't replace a good explanation. I consider the article to be a stub now, and valid and clean implementations could be added (I plan to). I also didn't keep the external links, that were not even really related to tree traversal, but merely to the use of graphs in the context of database, and probably came from a web development background (PHP and MySQL related links).

There are surely far better and more classic references to the subject, but the O'Reilly book is the one where I learned tree traversal and where I verified my stub. In particular, I suspect there is a treatment of trees and corresponding algorithms in The Art of Computer Programming, but I don't have it at hand.

Nowhere man 22:15, 1 December 2006 (UTC)

Reverse Polish Notation[edit]

The reverse polish notation used in HP calculators is the postfix, not the prefix notation. I don't know English enough to rewrite...

Changes on 14 Feb 07[edit]

To anyone watching this article, let me know what you think of the modifications. Restructured it quite a bit, no doubt slipped some typos/mistakes in, but I tried to make it look a bit more professional.

Also changed all the pseudocode to be consistent with one another (some were using curly braces to mark blocks, others just used whitespace - I started at the top where there was whitespace delimited blocks, and made the rest like that), and completely changed the algorithm for iterative/explicit stack based traversals. Let me know if I stuffed it up ! The original code definitely works, but it's possible I mucked up the pseudocode translation. Benefit of the new pseudocode is that at any point the direction could be changed (just use rights instead of lefts, lefts instead of rights), even mid traversal... and that the stack based implementation is virtually identical to the parent pointers implementation.

Also added an example for how to in-order traverse a threaded tree.

Phew. Over an hour down the drain, hope somebody finds it useful =P Themania 06:24, 28 February 2007 (UTC)

It looks great. I'll be reviewing it for stylistic concerns, but that's a lot of useful information you've added in. — Edward Z. Yang(Talk) 22:48, 28 February 2007 (UTC)
Thanks Edward =) apologies about reverting your revert - I'm pretty confident that the anomynous ip-logged user was correct, although reverting reverts should probably be mentioned on the talk page..? —The preceding unsigned comment was added by Themania (talkcontribs) 00:11, 1 March 2007 (UTC).
No, it's okay. It's tough to tell whether or not an edit is legit when there's no edit summary given. — Edward Z. Yang(Talk) 02:29, 1 March 2007 (UTC)
Would be, especially for non user edits. Just reassuring to know that there's people watching =) Themania 15:15, 1 March 2007 (UTC)

Problem with Iterative Solution[edit]

inorder(node)

while hasleftchild(node) do
  node = node.left
do
  visit(node)
  if not (hasrightchild(node)) then
    node = node.right // <------------------ look here
  else
    node = node.right // <------------------ and here
  while hasleftchild(node) do
    node = node.left
while node ≠ null

This can't be right... Philfreo 18:59, 23 March 2007 (UTC)

You're right, it's wrong. The inner while should have been under the then. I've fixed the article. Note that this is not just some iterative solution, it is only for a threaded tree, which essentially always has pointers to skip directly to the next inorder node from a node without a right child, so it happens to have a very simple inorder walk because of the extra threading. -R. S. Shaw 03:31, 24 March 2007 (UTC)

Looking at the previous question, I'm still not sure how this can work. If node does not have a right child, how can you do "else node = node.right" ? According to the graph at the top of the article, once the inorder traversal got to 'A' and there are no child nodes, then it goes back to its parent node.

Maybe something is going on at visit(node) that I don't understand.

inorder(node)

 while hasleftchild(node) do
   node = node.left
 do
   visit(node)
   if (hasrightchild(node)) then
     node = node.right
     while hasleftchild(node) do
       node = node.left
   else
     node = node.right //? here
 while node ≠ null

Ddgun (talk) 16:48, 12 February 2008 (UTC)

Apparently you're overlooking the word threaded. It's important. See Threaded binary tree. -R. S. Shaw (talk) 22:34, 13 February 2008 (UTC)

Preorder Iterative Solution in Java[edit]

I think the following code is a nice pre-order iterative traversal, using Java code.

I do think that the comment about iterative solutions being easily derived from the recursive ones is not helpful - at least I had a hard time getting solutions that I liked.

I did find nice solutions to all three traversals at the following page: http://discuss.techinterview.org/default.asp?interview.11.318495.11

     void preOrder (TreeNode root) {  
        Stack <TreeNode> s = new Stack <TreeNode> ();
        TreeNode n = root;
     
        s.push (root);
        while (!s.empty()) {
           n = s.pop();
           if (n != null) {
              System.out.print (" " + n);
              s.push (n.right);
              s.push (n.left);
           } // end if this node exists
        } // end while there are nodes to visit
     } // end method preOrder

nduchon@umuc.edu —Preceding unsigned comment added by 70.104.232.232 (talk) 16:00, August 30, 2007 (UTC)

Non-binary trees[edit]

This article seem to focus exclusively on the traversal of binary trees. My question is, if we want to include something about, for instance, traversal of directories on disk, should the focus of this article be changed, or should it be renamed to "binary tree traversal" and a more general article started? I am leaning towards the latter, but want more input than my own before I do it. W (talk) 13:55, 9 May 2008 (UTC)

I think we should just change everything to support all kinds of trees and mention somewhere how they can be done a little differently for binary trees. asmeurer (talk | contribs) 18:42, 2 July 2012 (UTC)
Agreed. The use of the terms "left" and "right" is very misleading for a "tree traversal" article and might lead people who don't know any better to think that all trees are binary. — Preceding unsigned comment added by 82.9.176.129 (talk) 02:22, 24 February 2014 (UTC)

Traversal - Example[edit]

Hi, i'm sry, but i don't really understand why the inorder-way in the example ends with "H I" and not with "I H". G's the first right child of the root. There's no left child of G, so we go to I and I' only child is H, so my intuition says there's no way in generell to "skip" a node. And is there a difference mentionable between "rightnode" and "rightchild" ? (btw is there a reason to write rightchild together or divided "right child"...). Sorry for faultily english. If someone's got the time please post me here that the question is answered. Thx a lot. --WissensDürster (talk) 19:29, 24 January 2009 (UTC)

I guess this answer would help you right now but maybe someone else will read it. I'd agree that the order is wrong for the "inorder" example. It doesn't make sense to skip this node. G I H should ne the right order! 188.101.213.177 (talk) 10:52, 15 August 2012 (UTC)

Traversal - Terminology[edit]

All the kinds of traversal say, e.g. 'visit the left subtree; visit the root; visit the right subtree' Surely it should be 'visit the node' rather than 'visit the root'. We do NOT keep going back to the root. JamesHDavenport (talk) 23:04, 17 March 2010 (UTC)

All of the algorithms for traversals detailed here (pre-order, in-order or symmetric-order, and post-order) are depth-first traversals. They traverse the nodes of the tree in the same order, but they "visit" them at different times. However, "visit the root" is correct terminology because it is a recursive algorithm. For example, when traversing the right sub-tree, "root" becomes the root of the right sub-tree. Xonev (talk) 19:57, 14 April 2010 (UTC)

Sure, but the article is titled "tree traversal", not "binary tree traversal", even though the term "left subtree" is completely meaningless for most other types of tree structure. The problem here is that the article uses very tree-type-specific and context-specific language and yet purports to be about trees in general. — Preceding unsigned comment added by 82.9.176.129 (talk) 02:27, 24 February 2014 (UTC)

iterativePostorder()??[edit]

I'm not convinced iterativePostorder() is correct. I've tried coding it up in Java and could not get it to work - although I accept it may be my own inability! A post-order tree traversal is the most difficult to implement of all the methods.

What I do know is that the pseudo code is poorly formatted with respect to the if-elseif-else block. The use of brackets may take up more lines but eliminates error and reader confusion.

I have a slight problem with the algorithms presented. They are primarily for binary trees with the nodes having left and right child nodes. However, the article title is "Tree Traversal" and not "Binary Tree Traversal". Thus, any algorithms presented should strictly be for general trees; ie a variable list of child nodes. This is what I'm trying to implement, the reason why I looked at this article and as a result have found the article confusing and of little use for general tree traversal. — Preceding unsigned comment added by 81.187.174.42 (talk) 09:48, 11 August 2011 (UTC)

References and proper citing[edit]

I have given a reference for the Recursive Traversals in C section. I've also put a <references/> tag under the section References. Please cite the books and the pdf properly in their respective places. This will make the page look good and maintain uniformity. Thanks!Face-smile.svg
BPositive (talk) 08:00, 6 December 2011 (UTC)

Shouldn't this be graph traversals?[edit]

As trees are just acyclic graphs, there should be a general page Graph traversals and as part of that page we should have tree traversals. Do you agree? --Vitalij zad (talk) 13:02, 4 March 2012 (UTC)

I agree. This article is very misleading, because it only deals with binary tree traversal and yet it's entitled just "Tree Traversal". It's also linked from the Graph Traversal article and referred to as a "special case of graph traversal", when it's really a "special case of a special case of graph traversal". As it stands, Wikipedia does not have an article that can be legitimately titled "Tree Traversal" -- so I think this should either be merged into Graph Traversal, renamed to "Binary Tree Traversal" or expanded so as to not be misleading.

Iterative traversal with parent pointers[edit]

I've replaced this code with a version that is more clear and practical for use. It only needs to keep the current node and not the previous node, so it can easily be expressed as a pair of first/next functions. The code is from my AVL tree at http://code.google.com/p/badvpn/source/browse/trunk/structure/BAVL.h#685 and I've been using it for a long time with no problems. 193.77.101.149 (talk) 00:23, 20 July 2012 (UTC)

Postorder conspicuously missing from 'Uses' section[edit]

Does anyone know a use for it? (If not, can I just add that it's useless and make someone prove otherwise? Just kidding.) Will Faught (talk) 22:20, 26 August 2012 (UTC)

Traversals on linearly mapped binary trees[edit]

The main article treats binary trees inherently as a nonlinear data structure, however they can be easily mapped to one (see https://en.wikipedia.org/wiki/Binary_tree#Arrays for a nice pictorial example). As a linear data structure, the traversal is trivial. This requires that the map to the linear array follows the traversal desired.

These mappings do not provide for fast (re)balancing. Groups of nodes are implied by the positions in the array, so moving a group generally requires moving the contents of all associated nodes (as opposed to generic binary trees).

In addition to an accelerated traversal, these maps provide controlled data locality, potentially improving performance in tree searches (which these structures are typically used for). Allocation on the fly guarantees no data locality at all, which reduces the efficiency of both tree searches and traversals.

As a result, linear mapped binary trees are particularly suited for fast tree searches and traversals on static binary search trees, where the tree structure is preserved (though member variables may change).

Qm physics (talk) 04:32, 10 March 2014 (UTC)

including recursively / including corecursively[edit]

The sentence containing these 2 phrases is quite clumsy. I'm not even sure what is really meant, but perhaps "using recursion" and "using corecursion" express the idea properly. — Preceding unsigned comment added by 68.183.92.210 (talk) 20:25, 14 May 2014 (UTC)

Morris threading[edit]

"It is more prone to errors when both the children are not present and both values of nodes point to their ancestors" is nonsensical. It implies that no (or maybe 1?) children are present, but the values point to something?! — Preceding unsigned comment added by 68.183.92.210 (talk) 21:27, 14 May 2014 (UTC)

Broken links[edit]

There are several broken links pointing to and within this page. E.g. https://en.wikipedia.org/wiki/Inorder_traversal#Inorder_traversal (not sure where I found that link). Additionally links are broken within the page, e.g. "threading the tree"

I don't know enough about editing Wikipedia to know a way to find all these links but I thought I would point it out as there seems to have been some work done on this. Thanks!

Chris Alexander UK (talk) 19:10, 19 May 2014 (UTC)