SEN2212 · Week 2 · Introduction to different tree structures.

Trees: terminology, binary trees and traversals

Terms such as root, leaf, depth and height, general and binary trees, preorder/inorder/postorder/level-order traces, and expression trees.

treerootleafparentchildsiblingdepthheightdegreesubtreebinary treefull binary treecomplete binary treepreorderinorderpostorderlevel-orderexpression treefirst-child next-sibling

Lists, stacks and queues (SEN2211) were linear structures: each element had at most one “next”. A tree is a hierarchical structure: an element can have many “children”. File systems, HTML documents, a compiler’s expression trees and database indexes are all trees. The next six weeks of this course (BST, AVL, red-black, heap) build on the terms on this page.

The questions from this week in the exam are: terminology (depth, height, number of leaves in a given tree), traversal traces (preorder, inorder, postorder, level-order), expression trees (build from postfix, evaluate) and building a tree from two traversals.

Terminology

Let’s take this general tree as our example:

            A
         /  |  \
        B   C   D
       / \     / \
      E   F   G   H
              |
              I
TermMeaningIn the example
rootthe only node with no parentA
parent / childdirectly connected upper / lower nodeG’s parent is D, its child is I
siblingchildren of the same parentB, C, D
leafa node with no childrenE, F, C, I, H
internal nodea node with at least one childA, B, D, G
degreenumber of childrenA: 3, G: 1
ancestor / descendantnodes on the path from the root to a node / nodes in its subtreeI’s ancestors are G, D, A
depthnumber of edges from the root to the nodeI: 3
heightnumber of edges from the node to the deepest leafD: 2, tree: 3
subtreea node and all its descendantsD, G, H, I

Two basic facts: a tree with n nodes has n - 1 edges (every node except the root has exactly one parent edge). There is exactly one path from the root to any node.

PITFALL · depth and height are measured in opposite directions. Depth goes top to bottom (the root has depth 0), height goes bottom to top (a leaf has height 0). Some sources count nodes, not edges. In this course and in Weiss we count edges; the height of an empty tree is -1.

Storing a general tree: first-child, next-sibling

If you do not know how many children a node will have, you cannot put a fixed number of references in each node. The solution: keep two references in each node, the first child and the next sibling on the right.

class TreeNode {
    String element;
    TreeNode firstChild;   // leftmost child
    TreeNode nextSibling;  // sibling to the right
}

In the tree above, A.firstChild = B, B.nextSibling = C, C.nextSibling = D, D.firstChild = G. This representation actually turns any general tree into a binary tree.

For a general tree, preorder (the node first, then its children from left to right) and postorder (the children first, then the node) are defined:

preorder : A B E F C D G I H
postorder: E F B C I G H D A

File system example: printing a directory listing with indentation is preorder; computing the total size of a directory is postorder (you need the sizes of the subdirectories first).

Binary trees

In a binary tree every node has at most two children, and the children are distinguished as left and right. A node that has only a right child is a different tree from one that has only a left child.

class Node {
    int element;
    Node left, right;
    Node(int e) { element = e; }
}

Special kinds of binary trees

KindDefinition
full (proper)every node has 0 or 2 children
perfectfull and all leaves at the same depth
completeevery level is full except the last, and the last level is filled from left to right

The complete tree will be the shape of a heap in week 7. The important numbers:

at most 2h+1−1 nodes for height h,h≥⌊log⁡2n⌋ for n nodes\text{at most } 2^{h+1} - 1 \text{ nodes for height } h, \qquad h \ge \lfloor \log_2 n \rfloor \text{ for } n \text{ nodes}

In the worst case (every node has a single child) the height is n−1n - 1 and the tree degenerates into a linked list. Since the running time of tree operations depends on the height, keeping the tree short is the main theme of the coming weeks.

Traversals

Let’s trace the four traversals on this binary tree:

          A
        /   \
       B     C
      / \     \
     D   E     F
        /     / \
       G     H   I
TraversalRuleResult
preorderroot, left, rightA B D E G C F H I
inorderleft, root, rightD B G E A C H F I
postorderleft, right, rootD G E B H I F C A
level-orderlevel by level, left to rightA B C D E F G H I

The code is three lines; only the position of the “visit” line changes:

static void preorder(Node n) {
    if (n == null) return;
    visit(n);              // first
    preorder(n.left);
    preorder(n.right);
}
static void inorder(Node n) {
    if (n == null) return;
    inorder(n.left);
    visit(n);              // in the middle
    inorder(n.right);
}
static void postorder(Node n) {
    if (n == null) return;
    postorder(n.left);
    postorder(n.right);
    visit(n);              // last
}

Level-order is not recursive; it uses a queue: put the root in the queue, and at each step remove from the front, visit, and add its children (left first) to the back.

static void levelOrder(Node root) {
    Queue<Node> q = new ArrayDeque<>();
    if (root != null) q.add(root);
    while (!q.isEmpty()) {
        Node n = q.poll();
        visit(n);
        if (n.left != null) q.add(n.left);
        if (n.right != null) q.add(n.right);
    }
}

All four visit each node once: O(n)O(n) time. The recursive ones use O(h)O(h) stack memory; level-order uses queue memory as large as the widest level.

TIP · the hand-traversal trick. Imagine a line that starts on the left and walks counterclockwise around the tree. If you write a node when the line touches its left side, you get preorder; when it touches the bottom, inorder; when it touches the right side, postorder.

Expression trees

In an expression tree the leaves are operands (numbers or variables) and the internal nodes are operators. (3 + 4) * (5 - 2):

          *
        /   \
       +     -
      / \   / \
     3   4 5   2
  • postorder → postfix: 3 4 + 5 2 - *
  • preorder → prefix: * + 3 4 - 5 2
  • inorder + parentheses → infix: ((3 + 4) * (5 - 2))
  • value: evaluate in postorder: first the two subtrees, then the operator → 7 * 3 = 21

Building a tree from postfix

It is the same as the postfix evaluation algorithm from SEN2211, but you push nodes instead of numbers:

  1. If an operand arrives, make a single-node tree and push it.
  2. If an operator arrives, pop the right subtree first, then the left, make an operator node, and push it.
  3. At the end exactly one tree is left on the stack.

The stack state for 6 2 / 1 + 4 *:

6        -> [6]
2        -> [6, 2]
/        -> [(6/2)]
1        -> [(6/2), 1]
+        -> [((6/2)+1)]
4        -> [((6/2)+1), 4]
*        -> [(((6/2)+1)*4)]     value 16

Building a tree from two traversals

Preorder (or postorder) tells the root, and inorder separates left from right. The algorithm:

  1. The first element of the preorder is the root.
  2. Find the root in the inorder. What is to its left is the left subtree, what is to its right is the right subtree.
  3. In the preorder, the next elements after the root, as many as the left subtree has, are the left subtree’s preorder; the rest is the right’s.
  4. Repeat for each subtree.

Example: preorder A B D E C F, inorder D B E A F C.

root A      inorder: [D B E] A [F C]
left: pre B D E, in D B E -> root B, left D, right E
right: pre C F,   in F C   -> root C, left F

        A
       / \
      B   C
     / \  /
    D  E F
postorder: D E B F C A

The same is done with postorder + inorder; this time the root is the last element of the postorder.

Common mistakes

Wrong ideaThe truth
The height of a leaf is 1Edges are counted: 0. An empty tree is -1
The depth of the root is 10
Level-order is written with recursionIt is written with a queue; recursion gives DFS order
When building a tree from postfix, the first popped is the left childThe first popped is the RIGHT child (8 2 - → 8 - 2)
Inorder always gives the correct infix of an expression treeWithout parentheses, precedence is lost
Preorder + postorder determines the treeNot with single-child nodes; inorder is required
A node with only a right child is the same as one with only a left childThey are different trees in a binary tree
n edges in a tree with n nodesn - 1 edges

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

For the general tree below, give the depth of T, the height of the tree, the degree of N and the number of leaves.

          K
       /  |  \
      L   M   N
     / \      |
    O   P     Q
            / | \
           S  T  U
Show answer
depth(T) = 3, height = 3, degree(N) = 1, 6 leaves

Depth is the number of edges from the root to the node: K → N → Q → T, 3 edges.
The height of the tree is the depth of the deepest leaf: S, T, U are at depth 3, so the height is 3.
Degree is the number of children: N has a single child Q, so the degree is 1.
Leaves (no children): O, P, M, S, T, U → 6. Internal nodes: K, L, N, Q → 4.

Question 2easy

Give the preorder and inorder traversals of the binary tree below.

        1
       / \
      2   3
     /   / \
    4   5   6
     \     /
      7   8
Show answer
Preorder: 1 2 4 7 3 5 6 8; Inorder: 4 7 2 1 5 3 8 6

Preorder = root, left, right. 1 → left subtree (2, 4, 7) → right subtree (3, 5, 6, 8).
2 has no right child; 4 has no left child and its right child is 7. So 1 2 4 7, then 3 5 6 8.
Inorder = left, root, right. Go to the far left: 4 has no left child, so write 4, then its right child 7. Then 2, then the root 1.
On the right side: 5, 3, then 6's left child 8, then 6: 4 7 2 1 5 3 8 6.

Question 3easy

For the same tree as the previous question, give the postorder and level-order traversals.

        1
       / \
      2   3
     /   / \
    4   5   6
     \     /
      7   8
Show answer
Postorder: 7 4 2 5 8 6 3 1; Level-order: 1 2 3 4 5 6 7 8

Postorder = left, right, root. The root is always last. The subtree of 4: 7 4. Then 2. The right side: 5, then the subtree of 6 is 8 6, then 3. Finally 1.
Level-order uses a queue, level by level from left to right: level 0: 1; level 1: 2 3; level 2: 4 5 6; level 3: 7 8.

Question 4medium

Build the expression tree for the postfix expression 8 2 3 * - 4 2 / +. What is its prefix (preorder) form and its value?

Show answer
+ - 8 * 2 3 / 4 2, value 4

Use a stack: push a number as a single node; when an operator arrives, pop two nodes (right first, then left), make an operator node, and push it.
8, 2, 3 are pushed. *: (2*3). -: (8 - (2*3)). 4, 2 are pushed. /: (4/2). +: the root.
The tree: root +, left child -(8, *(2,3)), right child /(4,2). Preorder: + - 8 * 2 3 / 4 2.
Value: 8 - 6 = 2, 4 / 2 = 2, 2 + 2 = 4.

Question 5medium

A binary tree has preorder P Q S T R U V and inorder S Q T P U R V. What is its postorder traversal?

Show answer
S T Q U V R P

The first element of the preorder is the root: P. In the inorder, what is left of P (S Q T) is the left subtree, and what is right (U R V) is the right subtree.
The preorder of the left subtree is Q S T: root Q, inorder S Q T → left child S, right child T.
The preorder of the right subtree is R U V: root R, inorder U R V → left child U, right child V.
Postorder: left subtree (S T Q), right subtree (U V R), root P → S T Q U V R P.

Question 6medium

What is the maximum number of nodes in a binary tree of height 4? What is the minimum possible height of a binary tree with 100 nodes?

Show answer
31; 6

Depth d has at most 2d2^d nodes. For height h the total is 20+...+2h=2h+1−12^0 + ... + 2^h = 2^{h+1} - 1. h = 4 → 31.
The height of a binary tree with n nodes is at least ⌊log⁡2n⌋\lfloor \log_2 n \rfloor. 26=64≤100<128=272^6 = 64 \le 100 < 128 = 2^7, so 6.
Check: with height 5, at most 63 nodes would fit, which is not enough for 100.

Question 7medium

How many null child references (null links) does the 8-node binary tree in question 2 contain? State the general rule.

Show answer
9; a binary tree with n nodes has n + 1 null links

Each node has 2 references: 2n in total. Every node except the root is pointed to by exactly one reference: n - 1 non-null references.
Null ones: 2n - (n - 1) = n + 1. For n = 8, that is 9.
Counting by hand: the left of 4, both children of 7, the right of 2, both children of 5, both children of 8, the right of 6 → 9.

Question 8medium

A full binary tree (every node has 0 or 2 children) has 12 leaves. How many internal nodes and how many nodes in total does it have?

Show answer
11 internal, 23 total

In a full binary tree, the number of leaves L and the number of internal nodes I satisfy L = I + 1.
Why: start with a single node (L=1, I=0). Giving a leaf two children increases I by 1 and L by 1 (one leaf is gone, two arrive). The difference always stays 1.
L = 12 → I = 11, total 23.

Question 9easy

Which traversal of an expression tree produces the postfix expression? Which one produces the fully parenthesized infix expression?

Show answer
Postorder; inorder (with parentheses added around each operator subtree)

In postfix the operator comes after its two operands: left, right, root = postorder.
In prefix it comes first: preorder.
In infix it is in the middle: inorder. But plain inorder loses precedence, so you need to put each internal node's subtree in parentheses: ((3 + 4) * (5 - 2)).

Question 10medium

Write a recursive Java method int countLeaves(Node n) that returns the number of leaves in a binary tree (Node has fields left and right).

Show answer
null → 0; no children → 1; else countLeaves(left) + countLeaves(right)

Three cases: an empty tree has 0 leaves, a node with no children is 1 leaf, otherwise the sum of the two subtrees.

static int countLeaves(Node n) {
    if (n == null) return 0;
    if (n.left == null && n.right == null) return 1;
    return countLeaves(n.left) + countLeaves(n.right);
}
Each node is visited once: O(n). For the tree in question 2 the result is 3 (7, 5, 8).

Question 11medium

Write a recursive Java method int height(Node n) for a binary tree, using the convention height(null) = -1 so that a single node has height 0.

Show answer
null → -1; else 1 + max(height(left), height(right))

The height of a node is the height of the taller subtree plus 1. With an empty tree at -1, a leaf gives 1 + max(-1, -1) = 0.

static int height(Node n) {
    if (n == null) return -1;
    return 1 + Math.max(height(n.left), height(n.right));
}
For the tree in question 2 the result is 3 (1 → 2 → 4 → 7). O(n).

Question 12hard

Can the preorder and postorder traversals together always determine a binary tree uniquely? Justify with an example.

Show answer
No; A with only a left child B and A with only a right child B both give preorder A B and postorder B A

Think of two trees: (1) A with only a left child B, (2) A with only a right child B.
Both have preorder A B and postorder B A. But the inorder differs: (1) B A, (2) A B.
Preorder or postorder gives the root, and inorder separates left from right. If a node with a single child exists, you need the inorder to build the tree.

Verification: All traversal orders, depth/height/degree values, expression tree results, the postorder of trees built from preorder+inorder, the null link counts and the L = I + 1 property were computed with Java (verify/SEN2212/W02.java, java W02.java).

Review card

Root: no parent. Leaf: no children. Siblings: same parent. depth(x) = number of edges from the root to x. height(x) = number of edges from x to the deepest leaf. Height of the tree = height of the root. Convention: height(null) = -1, leaf = 0. Degree = number of children. n nodes → n-1 edges. Binary tree, height h: at most 2^(h+1) - 1 nodes, at most 2^h leaves. n nodes: height at least floor(log2 n), at most n-1. Number of null links is n+1. Full (0 or 2 children): leaves = internal nodes + 1. Complete: all levels full except the last, last level filled from the left (heap shape). PRE: root-left-right IN: left-root-right POST: left-right-root LEVEL: queue. Expression tree: post → postfix, pre → prefix, in + parentheses → infix. Tree from postfix: stack; at an operator pop the RIGHT first, then the LEFT. To build a tree you need inorder + (pre or post); pre + post is not enough.