Skip to content

Tree traversals

A recursive walk visits every node of a tree once. Printing a node before, between or after its two subtrees gives preorder, inorder or postorder, and the same pattern measures a tree.

Helps to know firstBinary trees

Helps to know first
This topic

First, the picture

How do you print every key of a tree, each exactly once? One short recursive function does it. Watch where it prints.

Three ways to walk a tree

One route round the tree; a node prints before, between or after its subtrees

void preorder(const struct tnode *t){    if (t == NULL)        return;    printf("%d ", t->key);    preorder(t->left);    preorder(t->right);}    printf("preorder: ");    preorder(root);    printf("\ninorder: ");    inorder(root);    printf("\npostorder: ");    postorder(root);    printf("\n");

preorder(root): print each node before its subtrees.

calls
0
stack depth
0
Order

Output

preorder: 
0.00 / 26.60 s
Describe this picture

A picture across the frame, with the code under it. On the left is the house tree: 50 at the root, 30 and 70 under it, 20, 40, 60 and 80 as leaves, each node a box with its key, its address under it and two dots on its lower edge for left and right. A small round marker travels round the outside of the tree, and a tag “t” sits above the node the current call is on. On the right is the stack of calls, one card for each call of the walk that has not returned yet, the first at the top: each card is titled with the function and the key, such as preorder(30), or preorder(NULL) for an empty subtree, and holds t’s value, an address or NULL. Under both is a row that fills with the keys as they are printed, and the nodes already printed are tinted. The code pane shows the walk being played, preorder, inorder or postorder, and lines 94 to 100 of main, with the line about to run marked. The clip plays the preorder walk once, about 27 seconds. The marker starts on the left of 50; 50 is printed at once, the marker moves down to the left of 30 and a second card appears, 30 is printed, then 20. A call on an empty subtree adds a card for half a second and takes it away, and the marker stays where it was. Back at 20, the marker passes under it, then round its right side, and the card for 20 goes; the marker passes under 30 and down to the left of 40, and so on round the tree, ending on the right of 50 with the row reading 50 30 20 40 70 60 80. Under the picture are one sentence on the current step, the readouts “calls” and “stack depth”, the control and the output. The control, “Order”, has the positions “preorder”, “inorder” and “postorder”; a press plays that walk from its start. The marker takes the same route each time, and only the moment a node is printed changes: as the marker passes the node’s left, underneath it, or its right. The transport plays and pauses, steps one line back or forward, and scrubs; a paused step is kept in the page address as walks.step, and the order as walks.order.

One route, three moments

Here is the walk the clip plays:

void preorder(const struct tnode *t)
{
    if (t == NULL)
        return;
    printf("%d ", t->key);
    preorder(t->left);
    preorder(t->right);
}

It says: an empty tree has nothing to print; otherwise print this node, then walk the left subtree the same way, then the right. The function calls itself, which is recursion: each call handles one node and hands its two subtrees to two more calls of itself. The calls on NULL are where it stops.

Follow the cards. preorder(50) prints 50 and calls preorder(30), which prints 30 and calls preorder(20), which prints 20 and calls preorder(NULL) for 20’s left child. That call returns at once, and so does the one for 20’s right child, and preorder(20) is done. Its card goes, and the walk is back in preorder(30), which now calls preorder(40). At any moment the cards are the path from the root down to the node the walk is at: 50, 30, 20 when it is at 20.

Now the marker. Picture a line drawn tight round the outside of the tree, starting on the left of the root. It passes each node three times: on its left as the call on that node begins, underneath it once the left subtree is done, and on its right once both subtrees are done. The three walks follow exactly this route. They differ only in where they print:

  • Preorder prints a node as the marker passes its left, before either subtree: 50 30 20 40 70 60 80.
  • Inorder prints it underneath, between the two subtrees: 20 30 40 50 60 70 80.
  • Postorder prints it on its right, after both: 20 40 30 60 80 70 50.

Switch “Order” to inorder and watch it again: the cards and the marker make the same moves, and only the moments the row fills are different. Then postorder.

Key idea

The three walks visit the nodes in the same order. What changes is when each node is printed: before, between or after its two subtrees.

The inorder line comes out sorted. That is the rule of a binary search tree at work: everything in a node’s left subtree is smaller and everything in its right subtree larger, so printing the left subtree, then the node, then the right subtree prints the keys in increasing order. That is the promise made in Binary search trees.

The code and its cost

The three walks

void inorder(const struct tnode *t)
{
    if (t == NULL)
        return;
    inorder(t->left);
    printf("%d ", t->key);
    inorder(t->right);
}

void postorder(const struct tnode *t)
{
    if (t == NULL)
        return;
    postorder(t->left);
    postorder(t->right);
    printf("%d ", t->key);
}

The bodies are the same three lines in a different order. The printf moves; the two calls stay where they are.

What it costs

Each walk makes one call for every node and one for every empty child. A tree of n nodes has n + 1 NULL pointers (Binary trees, 12.1), so a walk makes n + (n + 1) = 2n + 1 calls: 15 for the house tree’s 7 nodes, which is what the “calls” readout ends on. Each call does a fixed amount of work, so the walk takes a number of steps proportional to n.

The stack holds one card per call that has not returned, and those calls are the path from the root to where the walk is, plus one call on NULL at the bottom. So the stack is as deep as the tree’s height plus two: here 2 + 2 = 4 cards (50, 30, 20 and an empty child), the most the clip shows. A tree of a million nodes with every level full but the last has height 19, and its walk is at most 21 cards deep; a chain of a million nodes would need a million and one. Traversals with a stack or a queue walks a tree with no recursion at all.

Measuring a tree the same way

The same pattern answers questions about a tree: find the answer for each subtree, then combine them.

int count(const struct tnode *t)
{
    if (t == NULL)
        return 0;
    int l = count(t->left);
    int r = count(t->right);
    return 1 + l + r;
}

int height(const struct tnode *t)
{
    if (t == NULL)
        return -1;
    int l = height(t->left);
    int r = height(t->right);
    return 1 + (l > r ? l : r);
}

count adds 1 for the node to the counts of its two subtrees, and an empty tree has 0. height adds 1 to the taller subtree’s height, and an empty tree has height −1, so a single node gets 1 + (−1) = 0, as Binary trees defined it. leaves returns 1 at a node with no children and adds up the two sides elsewhere. On the house tree the program prints count 7, height 2, leaves 4. These are postorder walks: each node’s answer is ready only after both of its subtrees have answered.

Which order for which job

  • Freeing a tree: postorder. A node is freed after both its subtrees, so its pointers are still there to follow when they are needed. free_tree in the program is a postorder walk; it frees 20, 40, 30, 60, 80, 70 and then 50.
  • Copying a tree: preorder. Make the copy of a node first, then copy its subtrees and hang them under it.
  • Printing an expression. The three orders of an expression tree are its three written forms, prefix, infix and postfix: the worked example below, and Infix to postfix.

Running it yourself

The code pane shows one walk and the lines of main that call the three. The full program, traversals.c, has the struct, make (which takes a key and the two children, so main builds the tree from its leaves up: 20, 40, then 30 over them, and so on), the three walks, count, height, leaves, free_tree and main. Build and run it with:

gcc -std=c11 -Wall -Wextra -pedantic traversals.c -o traversals
./traversals

Worked example

Rebuilding a tree from two walks. A tree has preorder 1 2 4 5 3 6 and inorder 4 2 5 1 6 3. What is it?

The first preorder key is always the root: 1. In the inorder list, everything left of 1 is in its left subtree and everything right of it in its right subtree: 4 2 5 on the left, 6 3 on the right. The preorder list keeps the subtrees together too: after the root come the left subtree’s three keys, 2 4 5, then the right’s, 3 6.

Now do the same for each side. The left part has preorder 2 4 5 and inorder 4 2 5: root 2, with 4 on its left and 5 on its right. The right part has preorder 3 6 and inorder 6 3: root 3, and 6 is left of 3 in the inorder list, so 6 is 3’s left child.

        1
       / \
      2   3
     / \  /
    4  5 6

Its postorder is 4 5 2 6 3 1. The program rebuild.c does exactly this with a recursive rebuild(pre, in, n): it finds the root’s place k in in, rebuilds the left side from the next k keys of pre and the first k of in, the right side from the rest, and calls make on the root with the two. Run on these lists, it prints 4 5 2 6 3 1. Preorder alone would not do: 1 2 3, for example, is the preorder of a chain going left, a chain going right, and three other shapes.

An expression tree. The expression (8 − 2) × 3 is the tree with × at the root, the subtree of 8 − 2 on its left, and 3 on its right.

       ×
      / \
     −   3
    / \
   8   2
WalkOutputForm
preorder× − 8 2 3prefix: the operator before its operands
inorder8 − 2 × 3infix, but the brackets are lost
postorder8 2 − 3 ×postfix: what a stack machine evaluates

The inorder line reads as 8 − 6 if you calculate it with the usual rules, so an infix printer must add brackets around every subtree to keep the meaning. The postorder line needs none: Evaluating postfix computes it with one stack, and gets 18.

Two checks. What is the inorder walk of any binary search tree? (Its keys in increasing order.) How many calls does a walk make on a tree of 100 nodes? (201: 100 nodes and 101 empty children.)

Where it’s used

Freeing and copying linked trees. Every program that builds a tree from malloced nodes frees it with a postorder walk, and copies it with a preorder one.

Directory listings. A listing that shows each folder and then, indented, what is inside it, is a preorder walk of the folder tree.

Evaluating expressions. A calculator or compiler that holds an expression as a tree evaluates it in postorder: both operands first, then the operator.

Keys in order. An inorder walk lists a search tree’s keys sorted, which is how ordered maps hand back their keys one by one.

Reference card

Code or ideaMeaning
if (t == NULL) return;the empty tree: where every walk stops
preordernode, left subtree, right subtree
inorderleft subtree, node, right subtree; a search tree’s keys sorted
postorderleft subtree, right subtree, node; frees a tree
calls for n nodes2n + 1 (n nodes, n + 1 empty children)
stack depthheight + 2 cards: the path from the root plus a NULL call
count1 + count(left) + count(right); empty 0
height1 + the larger of the two heights; empty −1
rebuildingpreorder’s first key is the root; it splits the inorder list into left and right

Platform: C11, gcc on x86-64 Linux: int 4 bytes, pointers 8, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

Keep reading with a free account.

Trees is a members’ section. An account costs nothing.

By creating an account you accept the terms of use.

Sign in

Already have an account? Use the way you signed up.

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look