DSABeginner 14 min Lesson 11 of 20

Trees — Data That Branches

How tree structures model folders, categories and documents, plus the traversal orders you will use again and again.

DSA · Lesson 11 of 20
0/20 done(0%)

What is it? #

A tree is a set of nodes where each node has one parent and any number of children. One node at the top — the root — has no parent.

There are no loops. Follow parents upwards from any node and you always reach the root. That property is what makes trees easy to reason about and easy to walk.

The vocabulary is small: root at the top, leaves at the bottom with no children, depth is the distance from the root, and height is the distance from a node down to its deepest leaf.

A binary tree restricts each node to at most two children. That restriction unlocks useful structures, including the binary search tree and heap covered next.

Think of it like this #

A folder on your computer. It contains files and other folders, which contain more of both. There is one top-level folder, no folder is inside itself, and every file has exactly one path back to the top.

An organisation chart works the same way: one head, each person reporting to one manager, no circular reporting.

Simple example #

A product category tree: Electronics contains Phones and Laptops, Phones contains Android and iOS. You need to list everything under a category, count the leaves, and find how deep the tree goes.

Code #

PYTHON
class TreeNode:
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, child):
        self.children.append(child)
        return child


root = TreeNode("Electronics")
phones = root.add(TreeNode("Phones"))
laptops = root.add(TreeNode("Laptops"))
phones.add(TreeNode("Android"))
phones.add(TreeNode("iOS"))
laptops.add(TreeNode("Ultrabooks"))


def height(node):
    if not node.children:
        return 1                                  # a leaf is height 1
    return 1 + max(height(child) for child in node.children)


def leaves(node):
    if not node.children:
        return [node.name]
    result = []
    for child in node.children:
        result.extend(leaves(child))
    return result


def show(node, depth=0):
    print("  " * depth + node.name)
    for child in node.children:
        show(child, depth + 1)


show(root)
print(height(root))      # 3
print(leaves(root))      # ['Android', 'iOS', 'Ultrabooks']


# Binary tree traversals — the three classic orders
class BinaryNode:
    def __init__(self, value, left=None, right=None):
        self.value, self.left, self.right = value, left, right


tree = BinaryNode(8, BinaryNode(3, BinaryNode(1), BinaryNode(6)), BinaryNode(10))


def in_order(node, out=None):        # left, self, right -> sorted for a BST
    out = [] if out is None else out
    if node:
        in_order(node.left, out)
        out.append(node.value)
        in_order(node.right, out)
    return out


def pre_order(node, out=None):       # self, left, right -> copying a tree
    out = [] if out is None else out
    if node:
        out.append(node.value)
        pre_order(node.left, out)
        pre_order(node.right, out)
    return out


def post_order(node, out=None):      # left, right, self -> deleting, folder sizes
    out = [] if out is None else out
    if node:
        post_order(node.left, out)
        post_order(node.right, out)
        out.append(node.value)
    return out


print(in_order(tree))    # [1, 3, 6, 8, 10]
print(pre_order(tree))   # [8, 3, 1, 6, 10]
print(post_order(tree))  # [1, 6, 3, 10, 8]
TEXT
        Electronics                 depth 0   (root)
        /         \
     Phones     Laptops             depth 1
     /    \         \
 Android  iOS    Ultrabooks         depth 2   (leaves)

How it works #

TreeNode holds a value and a list of children. That is all a general tree needs — the structure emerges from how nodes reference each other.

height is recursive because the definition is recursive: the height of a node is one more than the tallest of its children. A leaf hits the base case and returns 1.

leaves collects names from every node with no children, extending the result as it comes back up the recursion.

show prints with indentation proportional to depth, which is how folder listings and category trees are rendered.

The three traversal orders differ only in when the current node is handled relative to its children.

In-order (left, self, right) produces sorted output for a binary search tree, which is the next lesson.

Pre-order (self, left, right) visits a parent before its children — the right order for copying a tree or serialising it, because the parent must exist before the children can be attached.

Post-order (left, right, self) handles children first. That is what you want for deleting a tree, or for calculating folder sizes, since a folder's size depends on its contents being measured first.

Real-world use #

Trees are everywhere: file systems, HTML and the DOM, JSON documents, category hierarchies, comment threads, organisation charts, decision trees in machine learning, and the parse trees compilers build from source code.

Database indexes use B-trees, which are trees with many children per node, chosen because each node maps to a disk page and fewer levels means fewer disk reads.

Choosing a traversal is a real decision. Rendering a nested menu is pre-order. Computing directory sizes is post-order. Listing a sorted view of a BST is in-order.

Storing trees in a relational database is a recurring practical problem, usually solved with a parent_id column plus a recursive query, or with a materialised path like /electronics/phones/android that trades write cost for read simplicity.

Common mistakes #

  • Building a cycle by accident, which turns traversal into infinite recursion.
  • Deep recursion on an unbalanced tree, hitting the recursion limit — use an explicit stack.
  • Choosing the wrong traversal, for example deleting parents before children.
  • Confusing depth (distance from the root) with height (distance to the deepest leaf).
  • Querying a database once per node when one recursive query would fetch the whole tree.

Practice #

Build a tree representing a folder structure where each leaf has a file size. Write functions for total size (post-order), a printed listing with indentation (pre-order), and the deepest path in the tree. Then rewrite the listing using an explicit stack instead of recursion.

Quick quiz

  1. 1. What makes a structure a tree rather than a graph?

  2. 2. Which traversal gives sorted output for a binary search tree?

  3. 3. Which traversal suits calculating folder sizes?

  4. 4. What is the height of a single leaf node?

  5. 5. Why do database indexes use B-trees instead of binary trees?

Summary

  • A tree has one root, single parents and no cycles.
  • Recursion matches the shape of a tree, which is why traversals are short.
  • In-order sorts a BST, pre-order copies, post-order aggregates and deletes.
  • Depth measures from the root; height measures to the deepest leaf.
  • Trees model folders, documents, categories and database indexes.