Skip to main content

Section 31.2 Expression Trees and Tree Traversals

As a detailed example of a tree used to model a particular domain, we will consider expression trees. An expression tree is a binary tree (max of two children per node) that represents a mathematical expression. Each internal node stores an operator (like +, -, *, /) and each leaf node stores an operand (a number).
The root node is the multiplication operator (*). Its left child is the subtraction operator (-) with children 8 and 2. Its right child is the addition operator (+) with children 1 and 4.πŸ”—
Figure 31.2.1. Expression Tree for \((8 - 2) * (1 + 4)\)
The root of the expression tree represents the last operation to be performed. Its children represent the sub-expressions that are the inputs to that operation. We must compute \(8 - 2\) and \(1 + 4\) and then multiply their results. In traditional math notation we would use parentheses to show that those operations need to be performed first. The expression tree makes the order of operations explicit by the structure of the tree itself.
Most algorithms on a tree involve some form of traversal - visiting each node in the tree in a particular order. There are a few common ways to traverse a tree. One way is called pre-order traversal, where when we visit a node, we first process the node itself, then recursively visit its left child, and then recursively visit its right child.
In a post-order traversal, when we first enter a node, we recursively visit its left child, then recursively visit its right child, and only then process the node itself.
It is convention in both forms of traversal to visit the left child before the right child. For some algorithms the order will not matter, but for others it will be important to pick a direction and be consistent. For example, in our expression tree, we need to know if the subtraction node is calculating \((8 - 2)\) or \((2 - 8)\text{.}\) By sticking to a consistent left-right order, we can be sure that the left child is always the first operand and the right child is always the second operand.

Insight 31.2.1.

Pre and Post refer to the timing of when the node itself is processed relative to its children during a traversal. Pre (before) means the node is processed before its children, and Post (after) means the node is processed after its children.
In a binary tree, there is also another common traversal called in-order traversal. In this traversal, when we visit a node, we first recursively visit its left child, then process the node itself, and finally recursively visit its right child. In an expression tree, an in-order traversal will produce the expression in its traditional infix notation (with parentheses to indicate order of operations).

Activity 31.2.1. Traversals.

The expression tree for \((8 - 2) * (1 + 4)\) is shown below. Use the buttons to step through pre-order, in-order, and post-order traversals of the tree.
You can use the Parens in InOrder checkbox to toggle whether parentheses are shown in the in-order traversal.

Instructions.

When the > button is highlighted, an animation is prepared to run. Use the Step button to step through the animation one step at a time.
When no animation is in progress, you can use the data controls to start a new animation.
You can click and drag on the animation area to pan around. Use the Ctrl + mouse wheel (or touchpad scroll gesture) while over the animation area to zoom in and out.
  • Core Controls.
    • << : Skip to the beginning of the animation.
    • < : Step backwards one step in the animation.
    • > : Step forward one step in the animation.
    • >> : Skip to the end of the animation.
    • Auto Step Speed Set to anything other than off to automatically step through the animation at the selected speed.
    • Zoom Set the zoom level. You can also use Ctrl + Mouse Wheel to zoom in and out.
  • Data Controls.
    • Infix expression Enter an expression in infix notation. Use parentheses to indicate order of operations. Then press Load Expression
Here are the final patterns for each traversal:
  • Pre-order: * - 8 2 + 1 4
  • In-order: ( ( 8 - 2 ) * ( 1 + 4 ) ) If using parens
  • Post-order: 8 2 - 1 4 + *
Notice that in pre-order, the first item is always the root of the tree. Then comes its left child, followed by the left child’s subtree, then the right child and its subtree. In post-order, the first item is always the leftmost leaf node. The root of the tree is always the last item in post-order.
Part of deciding how to implement an algorithm on a tree is deciding which traversal to use. For example, to evaluate an expression tree (calculate the result of the expression it represents), we would want to use a post-order traversal. We need the result of the left and right sub-expressions before we can apply the operator at the parent node. In post-order traversal, we will always visit the children before the parent, so we can calculate the values of the children first and then use them to calculate the value of the parent. Click the Evaluate Expression button in the interactive above to see this in action.

Checkpoint 31.2.1.

Given the expression tree shown below:
An expression tree with the * at root. * has children 5 and +. + has children - and 6. - has children 3 and 2.πŸ”—
Arrange the blocks to show a preorder traversal.

Checkpoint 31.2.2.

Given the expression tree shown below:
An expression tree with the * at root. * has children 5 and +. + has children - and 6. - has children 3 and 2.πŸ”—
Arrange the blocks to show a postorder traversal.

Checkpoint 31.2.3.

You have attempted of activities on this page.