NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · May 2016

Question 5 of 8: Pointer-based Data Structures — Binary Tree Traversal

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format. 98-Comp-A4 Program Design and Data Structures, May 2016 — 3 hours, closed book, no calculator permitted. Eight questions of equal weight (20 marks each: some split as (a) 10 + (b) 10); candidates answer any five, so a complete paper is 100 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All eight questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written, but a clear, correctly reasoned pseudocode answer would earn the same marks.

Reference texts for this subject.

  • Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, 4th ed. — tree traversals (ch. 12), sorting and Quicksort (ch. 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — linked lists (ch. 3), binary search trees (ch. 4).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and templates (ch. 9–12), file streams (ch. 14).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/array I/O idioms (ch. 1, 7), pointers and structures (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — class templates and value semantics (ch. 3, 25–27).

The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.

Question 5: Pointer-based Data Structures — Binary Tree Traversal (20 marks: (a) 10, (b) 10)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Check: the printed TreeNode struct is copy-pasted from Question 4's ELEMENT. Its left/right fields are declared as struct element *, which does not compile (no member named element exists in this scope, and even if it did it would be the wrong type). This is fixed below to the obvious intended declaration, struct treenode *left, *right, self-referential exactly as the question's own name for the type requires.

Given. A binary tree node holding an int and two child pointers, with no ordering assumption stated (unlike a BST, nothing here requires left < node < right) — both functions must work for an arbitrary binary tree shape.

Find. (a) A function that prints every node's data in inorder (left, node, right) order. (b) A function returning the largest data value stored at a leaf (a node with no children) — not simply the largest value in the tree.

Approach. Both are textbook recursive tree walks: the base case is an empty subtree (root == NULL), and the recursive case combines the two child subtrees' results with the current node according to each function's own rule (print-in-order for (a), leaf-detection-and-max for (b)).

(a) inorder traversal (10 marks)

  1. State the recursive definition directly. Inorder traversal of a (possibly empty) tree is: traverse the left subtree, visit the root, traverse the right subtree — and traversing an empty subtree does nothing, which is exactly the required empty-tree behaviour.
    #include <stdio.h>
    
    typedef struct treenode {
        int data;
        struct treenode *left;
        struct treenode *right;
    } TreeNode;
    
    void inorder(TreeNode *root)
    {
        if (root == NULL)
            return;                 /* empty (sub)tree: nothing to print */
    
        inorder(root->left);
        printf("%d ", root->data);
        inorder(root->right);
    }
  2. Trace it on a small example tree (8 at the root; left subtree 3 with children 1 and 6, 6 having children 4 and 7; right subtree 10 with a right child 14, which itself has a left child 13): the recursion visits 1, 3, 4, 6, 7, 8, 10, 13, 14, in that order — each node's left subtree fully printed before the node itself, which is itself printed before its right subtree. $$\boxed{\text{inorder} = 1,3,4,6,7,8,10,13,14}$$

(b) find_max_leaf (10 marks)

  1. Distinguish "largest value in the tree" from "largest value at a leaf." A node with at least one child is never a candidate, however large its own data — only nodes where both left and right are NULL qualify. The recursive answer for a subtree is therefore: if this node is itself a leaf, its own value is the answer; otherwise, recurse into whichever children exist and take the larger of their answers.
  2. Write the function. An empty tree has no leaf at all; this is handled by returning a sentinel (here INT_MIN) that can never win a max comparison against a real leaf value found elsewhere in the recursion, and is flagged as an assumption since the question does not specify empty-tree behaviour for this function the way it does for inorder.
    #include <limits.h>
    
    int find_max_leaf(TreeNode *root)
    {
        int leftMax, rightMax;
    
        if (root == NULL)
            return INT_MIN;                      /* no leaf exists; see check note */
    
        if (root->left == NULL && root->right == NULL)
            return root->data;                   /* root itself is a leaf */
    
        leftMax  = find_max_leaf(root->left);
        rightMax = find_max_leaf(root->right);
        return (leftMax > rightMax) ? leftMax : rightMax;
    }
  3. Trace it on the same example tree. The leaves are 1, 4, 7 and 13 — node 14 is not a leaf, since it has a left child (13), even though 14 > 13. The recursion returns $\max(1,4,7,13) = 13$, not 14. $$\boxed{\text{find\_max\_leaf} = 13\ \text{(not 14, which has a child)}}$$

Check: assumes an empty tree passed to find_max_leaf returns INT_MIN. The question specifies empty-tree behaviour for inorder (print nothing) but not for find_max_leaf, which has no meaningful "largest leaf value" to report when there are no nodes at all. INT_MIN is chosen as a sentinel that never wins a comparison against a genuine leaf value; a caller that must distinguish "empty tree" from "a leaf legitimately holding INT_MIN" would need a separate boolean out-parameter.

Question 5 — results
QuantityValue
Example tree inorder sequence1, 3, 4, 6, 7, 8, 10, 13, 14
Leaves of the example tree1, 4, 7, 13
find_max_leaf(example tree)13
inorder(NULL)prints nothing
find_max_leaf(NULL)INT_MIN (sentinel; see the check note)