Skip to content

Binary trees

A binary tree is a set of nodes, each pointing to at most two children. Nodes scattered across the heap form a branching shape, and its height decides how much it can hold.

Helps to know firstSingly linked lists

Helps to know first
This topic

First, the picture

Five nodes on the heap, each with two pointers. What shape do they make? Watch the same arrows turn into a tree.

A tree hiding in memory

Five nodes at scattered addresses, joined by pointers

#include <stdio.h>#include <stdlib.h> struct tnode {    int key;    struct tnode *left, *right;}; struct tnode *new_node(int key){    struct tnode *n = malloc(sizeof *n);    if (n == NULL)        exit(1);    n->key = key;    n->left = NULL;    n->right = NULL;    return n;} int main(void){    struct tnode *d = new_node(4);    struct tnode *b = new_node(2);    struct tnode *e = new_node(5);    struct tnode *a = new_node(1);    struct tnode *c = new_node(3);    a->left = b;    a->right = c;    b->left = d;    b->right = e;    printf("root %d, children %d and %d\n", a->key, a->left->key, a->right->key);    free(d);    free(e);    free(b);    free(c);    free(a);    return 0;}

main has started: five pointers, none set yet.

Output

0.00 / 28.05 s
Describe this picture

The whole of tree.c, with the line about to run marked, beside a picture of memory. At the top is main’s card with its five pointers d, b, e, a and c, each showing the address it holds or ”?”, and under it, while new_node runs, that call’s card with key and n. Below the cards are the program’s nodes. Each node is a box holding its key, with its address under it and two small dots on its lower edge for left and right: a hollow dot is NULL, a filled dot has an arrow leaving it. The clip plays once, about 28 seconds. The first new_node runs line by line and the node for 4 appears at 0x1000, at the left of a row; the next four calls take a beat each, and the nodes for 2, 5, 1 and 3 appear to its right at 0x1020, 0x1040, 0x1060 and 0x1080, in the order they were made. Then four lines draw four arrows, one each, dipping under the row: from 1’s left dot to 2, from 1’s right dot to 3, from 2’s left dot to 4 and from 2’s right dot to 5. The picture pauses, then for three seconds the five boxes glide out of the row into a tree, 1 on top, 2 and 3 under it, 4 and 5 under 2, the arrows still attached and now pointing down. The output reads root 1, children 2 and 3, and the nodes are hatched as they are freed: 4, 5, 2, 3, then 1. Under the picture are one sentence on the current step and the output. The transport plays and pauses, steps one line back or forward, and scrubs; a paused step is kept in the page address as tree.step. On a phone the code comes first and the picture under it.

Five nodes, four arrows

The program makes five nodes with new_node, the function you met in Binary search trees: each call asks malloc for one node, writes its key and sets both of its pointers to NULL. The keys are made in the order 4, 2, 5, 1, 3, and the heap places the blocks one after another in that order, from 0x1000 to 0x1080. In memory there is no shape at all: just five boxes in a row, in the order they were asked for.

Then four lines join them:

a->left = b;
a->right = c;
b->left = d;
b->right = e;

Each line writes one address into one pointer, and each draws one arrow. The node for 1 now points to 2 and 3, and the node for 2 points to 4 and 5. The arrows cross the row in every direction, because the order on the heap has nothing to do with who points to whom.

Then the picture redraws the same five boxes and the same four arrows: 1 at the top, the nodes it points to below it, the nodes they point to below them. Nothing in memory changes during the glide. Every address under every box is the one it had in the row, and no byte is written. That drawing, with each node above the nodes it points to, is a binary tree: each node points to at most two others, its children, and every node except one is pointed to by exactly one parent.

Key idea

A tree is not a place in memory. It is the pattern the pointers make, and the nodes can sit anywhere on the heap.

printf then follows the pointers from the top: a->key is 1, a->left->key is 2 and a->right->key is 3, so it prints root 1, children 2 and 3. Last, the program frees the nodes, the two at the bottom first, then 2, then 3, then 1. A node is freed only after both of its children, so no node is freed while it still holds the only pointer to a node that has not been freed yet. Tree traversals frees a whole tree that way with one short function.

The code and its cost

The words

Here is the tree from the clip, with its keys:

        1
       / \
      2   3
     / \
    4   5
  • The root is the one node with no parent: 1. A program keeps a pointer to it, here a, and reaches every other node from there.
  • A node’s children are the nodes its two pointers point to; it is their parent. 2 and 3 are the children of 1, and 1 is their parent.
  • A leaf is a node with no children: 4, 5 and 3.
  • A node’s subtree is the node with everything below it. The subtree of 2 is 2, 4 and 5; it is the root’s left subtree, and the subtree of 3 is the right one.
  • The depth of a node counts the edges from the root down to it: 1 has depth 0, 2 and 3 have depth 1, 4 and 5 depth 2.
  • The height of a tree is the largest depth of any node, so this tree has height 2. Height counts edges, not nodes: a single node has height 0, and an empty tree, by agreement, height −1.

The node

struct tnode {
    int key;
    struct tnode *left, *right;
};

This is the struct of Binary search trees, and it is 24 bytes here: key at 0, 4 bytes of padding, left at 8 and right at 16. A missing child is a NULL pointer, drawn as a hollow dot. A leaf has two of them, so not every node has two children; every node has two pointers.

Count the pointers in the clip’s tree: five nodes have ten, four of them are arrows, and six are NULL. That holds for any binary tree: every node but the root has one arrow coming in, so n nodes have n − 1 arrows, and the other 2n − (n − 1) = n + 1 pointers are NULL.

How tall, how full

Each level of a binary tree can hold at most twice as many nodes as the level above it: 1 at depth 0, 2 at depth 1, 4 at depth 2, and 2ᵈ at depth d. So a tree of height h holds at most

1+2+4+⋯+2h=2h+1−11 + 2 + 4 + \dots + 2^h = 2^{h+1} - 1

nodes. Turn that round: to hold n nodes, a tree needs 2h+1−1≥n2^{h+1} - 1 \ge n, so its height is at least ⌊log₂ n⌋. For the clip’s five nodes that is ⌊log₂ 5⌋ = 2, the height they have. The other extreme is a chain, each node with one child, and its height is n − 1.

This is the number that matters later. Every search tree in this part of the course walks one path from the root, so its cost is its height, somewhere between about log₂ n and n − 1.

Full, complete and perfect

Three names describe how well a tree is filled:

  • Full: every node has 0 or 2 children, never 1.
  • Complete: every level is full except possibly the last, and the last is filled from the left with no gaps.
  • Perfect: every level is full. A perfect tree of height h has exactly 2h+1−12^{h+1} - 1 nodes.

The clip’s tree is full (1 and 2 have two children each, the rest none) and complete (levels 0 and 1 are full, and the last level holds 4 and 5 at its left). It is not perfect: a perfect tree of height 2 has 7 nodes, and this one has 5. Complete trees come back in Storing trees, where they fit an array without gaps, and in Binary heaps (14.1).

How many shapes

How many different binary trees can five nodes make, if only the shape counts? Watch the shapes for 1, 2, 3 and 4 nodes first.

Counting the shapes

Every binary tree with 1 to 4 nodes, then the count for 5

One node: one shape, a root on its own.

nodes
1
0.00 / 11.60 s
Describe this picture

A picture with no code. Each shape is drawn small: a dot for each node, the root’s dot in the accent colour, a line from each node down to each child, and a left child always below and to the left of its parent. A heading above the shapes gives the count. The replay steps through 1 node (one shape, a single dot), 2 nodes (two shapes: a root with a left child, a root with a right child), 3 nodes (five shapes: four chains bending left or right, and a root with a child on each side) and 4 nodes (14 shapes, in rows); then the shapes give way to the number 42 for 5 nodes, with the words “too many to draw here”. Under the picture are one sentence on each step and the readout “nodes”. The transport plays and pauses, steps back or forward, and scrubs; a paused step is kept in the page address as shapes.step.

The counts come from one idea. Pick how many of the other n − 1 nodes go into the root’s left subtree, say k; the rest go right. The number of shapes is the number of left shapes times the number of right shapes, added up over every k. For 4 nodes, the left subtree holds 0, 1, 2 or 3 of the other three, which gives 1 × 5 + 1 × 2 + 2 × 1 + 5 × 1 = 14 (left shapes × right shapes, for k = 0 to 3). These are the Catalan numbers, and they have a formula:

shapes(n)=1n+1(2nn)\text{shapes}(n) = \frac{1}{n+1}\binom{2n}{n}

with the binomial coefficient of Counting. They grow fast: 42 for 5 nodes, and 16,796 for 10.

Worked example

The words on the clip’s tree. Depths: 1 at 0; 2 and 3 at 1; 4 and 5 at 2. Height 2. Leaves 4, 5 and 3. Full and complete, not perfect. Six NULL pointers, which is n + 1 for n = 5.

The most nodes for a height. 2h+1−12^{h+1} - 1 gives:

Height hMost nodes
01
13
27
315
191,048,575

So a tree only 19 edges tall can hold over a million nodes, and a search that walks one path from its root looks at no more than 20 of them.

The least height for 1,000 nodes. Height 9 holds at most 210−12^{10} - 1 = 1,023 nodes, which is enough; height 8 holds at most 29−12^9 - 1 = 511, which is not. So 1,000 nodes need a height of at least 9, and ⌊log₂ 1000⌋ = 9 says the same.

Shapes, by the formula. For 3 nodes, C(6, 3)/4 = 20/4 = 5. For 4, C(8, 4)/5 = 70/5 = 14. For 5, C(10, 5)/6 = 252/6 = 42. The same numbers as the picture.

Three checks before you move on. A chain of 5 nodes has what height? (4: it has 4 edges.) Can a tree of height 2 hold 8 nodes? (No: at most 7.) And is the clip’s tree a binary search tree? (No: 4 and 5 sit in the left subtree of 2, but 5 is larger than 2. A binary search tree is a binary tree with an extra rule about its keys: Binary search trees.)

Where it’s used

Compilers. A compiler turns (8 - 2) * 3 into an expression tree: * at the root, with the tree of 8 - 2 on its left and 3 on its right. Each operator node has two children, its operands.

Decision trees. A decision tree in machine learning asks a yes-or-no question at each node and goes to one of two children: Decision trees.

Folders. A file system’s folders form a tree, though a folder can have any number of children; Storing trees shows how such a tree is stored in nodes with two pointers.

The rest of this part. Search trees (Chapter 13) add a rule about where keys go, and heaps (Chapter 14) add a different one. Both are binary trees first.

Reference card

Code or ideaMeaning
struct tnode { int key; struct tnode *left, *right; };a node: 24 bytes here (key 4, padding 4, left 8, right 8)
NULL childno child on that side; a leaf has two
root, parent, child, leaf, subtreethe node with no parent; the node pointing; the node pointed to; a node with no children; a node and all below it
depth of a nodeedges from the root to it
height of a treethe largest depth; one node 0, empty −1
n nodesn − 1 arrows, n + 1 NULL pointers
most nodes at height h2h+1−12^{h+1} - 1
least height for n nodes⌊log₂ n⌋ (a chain: n − 1)
full, complete, perfect0 or 2 children each; levels full but the last, filled from the left; every level full
shapes with n nodesC(2n, n)/(n + 1): 1, 2, 5, 14, 42

Platform: C11, gcc on x86-64 Linux: int 4 bytes, pointers 8, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

Keep reading with a free account.

Trees is a members’ section. An account costs nothing.

By creating an account you accept the terms of use.

Sign in

Already have an account? Use the way you signed up.

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look