Quiz 2

15. Binary Trees & Traversals

963 words
5 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# 15. Binary Trees & Traversals > **What problem does this solve?** Linked lists are linear — O(n) search.

15. Binary Trees & Traversals

What problem does this solve? Linked lists are linear — O(n) search. Trees are hierarchical, enabling O(log n) operations when balanced. Binary trees form the foundation for BSTs, heaps, AVL trees, and expression trees.

1. Tree Terminology

(Diagram)
TermDefinition
RootTopmost node (no parent)
LeafNode with no children
ParentDirect ancestor of a child
ChildDirect descendant
SiblingsNodes sharing the same parent
DepthDistance from root (root = 0)
HeightMax depth of any node
Full treeEvery node has 0 or 2 children
Complete treeAll levels filled except possibly last, filled left-to-right
Perfect treeAll internal nodes have 2 children AND all leaves have same depth

2. Binary Tree Node

python
# runnable
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
    def __repr__(self):
        return f"TreeNode({self.val})"
# Build a binary tree
#     1
#    / \
#   2   3
#  / \
# 4   5
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)

3. Tree Traversals

Mental Model

  • Preorder: Visit node, then left, then right (like reading a document: section, subsection)
  • Inorder: Visit left, then node, then right (sorted order in BST)
  • Postorder: Visit left, then right, then node (delete children before parent) (Diagram)
python
# runnable
class BinaryTree:
    def __init__(self, root=None):
        self.root = root
    def preorder(self, node=None):
        """Preorder: root → left → right"""
        if node is None:
            node = self.root
        result = []
        def _traverse(n):
            if n:
                result.append(n.val)
                _traverse(n.left)
                _traverse(n.right)
        _traverse(node)
        return result
    def inorder(self, node=None):
        """Inorder: left → root → right"""
        if node is None:
            node = self.root
        result = []
        def _traverse(n):
            if n:
                _traverse(n.left)
                result.append(n.val)
                _traverse(n.right)
        _traverse(node)
        return result
    def postorder(self, node=None):
        """Postorder: left → right → root"""
        if node is None:
            node = self.root
        result = []
        def _traverse(n):
            if n:
                _traverse(n.left)
                _traverse(n.right)
                result.append(n.val)
        _traverse(node)
        return result
    def level_order(self):
        """Level-order (BFS) traversal using a queue."""
        if not self.root:
            return []
        from collections import deque
        result = []
        q = deque([self.root])
        while q:
            node = q.popleft()
            result.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        return result
bt = BinaryTree(root)
print(f"Preorder:  {bt.preorder()}")    # [1, 2, 4, 5, 3]
print(f"Inorder:   {bt.inorder()}")     # [4, 2, 5, 1, 3]
print(f"Postorder: {bt.postorder()}")   # [4, 5, 2, 3, 1]
print(f"Level:     {bt.level_order()}") # [1, 2, 3, 4, 5]

Iterative Traversals

python
# runnable
def inorder_iterative(root):
    """Iterative inorder using explicit stack."""
    result = []
    stack = []
    curr = root
    while curr or stack:
        while curr:
            stack.append(curr)
            curr = curr.left
        curr = stack.pop()
        result.append(curr.val)
        curr = curr.right
    return result
def preorder_iterative(root):
    """Iterative preorder."""
    if not root:
        return []
    result = []
    stack = [root]
    while stack:
        curr = stack.pop()
        result.append(curr.val)
        if curr.right:
            stack.append(curr.right)
        if curr.left:
            stack.append(curr.left)
    return result
print(f"Inorder iterative: {inorder_iterative(root)}")
print(f"Preorder iterative: {preorder_iterative(root)}")

4. Applications of Traversals

TraversalUse Case
PreorderCopy/clone a tree, prefix notation
InorderBST sorted output, infix notation
PostorderDelete tree, postfix notation, expression tree evaluation
Level orderBFS, shortest path, serialization

5. Common Binary Tree Problems

Tree Height / Max Depth

python
# runnable
def max_depth(root):
    """Return maximum depth (height) of tree."""
    if not root:
        return 0
    return 1 + max(max_depth(root.left), max_depth(root.right))
print(f"Height: {max_depth(root)}")  # 3

Check if Tree is Balanced (Height difference ≤ 1)

python
# runnable
def is_balanced(root):
    """Check if tree is height-balanced."""
    def check(n):
        if not n:
            return 0  # Height = 0, balanced
        left = check(n.left)
        if left == -1:
            return -1
        right = check(n.right)
        if right == -1:
            return -1
        if abs(left - right) > 1:
            return -1
        return 1 + max(left, right)
    return check(root) != -1
# Balanced tree
balanced = BinaryTree(root)
print(f"Balanced: {is_balanced(balanced.root)}")  # True
# Unbalanced tree
unbalanced_root = TreeNode(1)
unbalanced_root.left = TreeNode(2)
unbalanced_root.left.left = TreeNode(3)
print(f"Unbalanced: {is_balanced(unbalanced_root)}")  # False

Serialize / Deserialize

python
# runnable
def serialize(root):
    """Convert tree to string using preorder with 'null' markers."""
    def _serialize(n, parts):
        if not n:
            parts.append("null")
            return
        parts.append(str(n.val))
        _serialize(n.left, parts)
        _serialize(n.right, parts)
    parts = []
    _serialize(root, parts)
    return ",".join(parts)
def deserialize(data):
    """Convert serialized string back to tree."""
    parts = data.split(",")
    idx = [0]
    def _deserialize():
        val = parts[idx[0]]
        idx[0] += 1
        if val == "null":
            return None
        node = TreeNode(int(val))
        node.left = _deserialize()
        node.right = _deserialize()
        return node
    return _deserialize()
data = serialize(root)
print(f"Serialized: {data}")
restored = deserialize(data)
print(f"Restored inorder: {inorder_iterative(restored)}")  # [4, 2, 5, 1, 3]

Practice Questions

Q1. Draw the tree with preorder [1, 2, 4, 5, 3] and inorder [4, 2, 5, 1, 3]. Q2. What's the maximum number of nodes in a binary tree of height h? Q3. Write a function to check if two binary trees are identical. Q4. Find the diameter (longest path between any two nodes) of a binary tree. Q5. What traversal would you use to delete all nodes in a tree? Q6. How can you determine if a binary tree is a BST using inorder traversal?
Answers
A1. Root = 1. From inorder: left subtree = [4, 2, 5], right = [3]. From preorder: 2 is left child of 1. Recursively: 4, 5 are children of 2.
A2. (2^{h+1} - 1) for a perfect tree of height h (root at height 0).
A3. Check if both None → True. If one None → False. If values differ → False. Recurse on left and right children.
A4. For each node, diameter = left_height + right_height. Max across all nodes is the answer.
A5. Postorder — delete children before parent. Deleting root first would lose access to children.
A6. Inorder traversal of a BST yields values in ascending order. If any pair violates this order, it's not a BST. Join Discord Previous14. Hash Tables — Dictionaries Under the HoodNext16. Binary Search Trees
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.