Intermediate: core algorithms · Trees and binary search trees · topic 31 of 61 · 30 min
Trees: words and shapes
Explanation
Why trees?
Arrays, stacks and linked lists put items in a line. Many things in life are not a line but a hierarchy: folders inside folders, a company org chart, an HTML page where tags sit inside tags (the DOM), a family tree, or product categories such as Electronics → Mobiles → Smartphones. A tree is the data structure for hierarchies. It also gives fast searching when it is kept in order (binary search trees, Topic 4) and fast "give me the smallest" when it is kept as a heap (Module 8).
The words
| Word | Meaning |
|---|---|
| Node | One item in the tree. It holds a value and links to its children. |
| Edge | The link from a parent to a child. A tree with n nodes has exactly n − 1 edges. |
| Root | The single node at the top. It has no parent. |
| Parent / child | If an edge goes from A down to B, A is the parent of B and B is a child of A. |
| Leaf | A node with no children. |
| Subtree | A node together with everything below it. Every node is the root of its own subtree. |
| Depth of a node | The number of edges from the root down to it. The root has depth 0. |
| Height of a node | The number of edges on the longest path from it down to a leaf. A leaf has height 0. |
| Height of a tree | The height of its root. |
A tree has no cycles: from the root there is exactly one path to every node. That single-path rule is what separates a tree from a general graph (Module 9).
Binary trees and their shapes
In a binary tree each node has at most two children, a left child and a right child. Left and right matter: a root with only a left child is a different tree from a root with only a right child.
- Full: every node has 0 or 2 children, never exactly 1.
- Complete: every level is completely filled except possibly the last, and the last level is filled from the left with no gaps. Heaps are complete trees.
- Perfect: every internal node has 2 children and all leaves are on the same level. A perfect tree of height h has 2^(h + 1) − 1 nodes, for example 7 nodes for height 2.
- Balanced (height-balanced): at every node, the heights of the left and right subtrees differ by at most 1. Its height is O(log n).
- Skewed (degenerate): every node has only one child, so the tree is really a linked list and its height is n − 1.
The shape decides the speed. Most tree operations walk from the root down one path, so they cost O(h), where h is the height. In a balanced tree h is about log₂ n (around 20 for a million nodes); in a skewed tree h is n − 1. That difference is the whole reason balanced trees exist.
Representation 1: linked nodes
The usual way is a small class with a value and two links. None means "no child". In this module every task gives you the same TreeNode class and a build(values) helper. build takes a level-order list, the way LeetCode shows trees: the root first, then its children left to right, then the next level, with None for a missing child.
1
/ \
2 3
/ \ \
4 5 6class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
root = build([1, 2, 3, 4, 5, None, 6])
print(root.val, root.left.val, root.right.val) # Output: 1 2 3
print(root.left.left.val, root.right.right.val) # Output: 4 6
print(root.right.left) # Output: NoneRepresentation 2: an array (heap layout)
A complete binary tree can live in a plain list with no links at all. Put the root at index 0 and fill each level left to right. Then for the node at index i: the left child is at 2i + 1, the right child at 2i + 2, and the parent at (i − 1) // 2. No pointers are stored, which saves memory and keeps the data side by side. Heaps (Module 8) use exactly this layout.
arr = [1, 2, 3, 4, 5, None, 6]
i = 1 # the node with value 2
print(arr[2 * i + 1], arr[2 * i + 2], arr[(i - 1) // 2]) # Output: 4 5 1Your first recursive tree function
Almost every tree function follows one template: handle the empty tree (None), then combine the answers of the left and right subtrees. Counting nodes: an empty tree has 0 nodes; otherwise it is 1 (this node) plus the count on the left plus the count on the right. It visits each node once, so it is O(n) time, and the recursion goes as deep as the tree, so it uses O(h) stack space.
def count_nodes(root):
if root is None:
return 0
return 1 + count_nodes(root.left) + count_nodes(root.right)
print(count_nodes(build([1, 2, 3, 4, 5, None, 6]))) # Output: 6Common mistakes
- Forgetting the empty tree. root.left on None raises AttributeError. Fix: start every function with if root is None.
- Mixing up depth and height, or edges and nodes. Fix: say "height in edges" or "depth in nodes" out loud, and test a single node.
- Treating a leaf as "a node with at most one child". A leaf has NO children: node.left is None and node.right is None.
- Assuming every binary tree is a BST or balanced. Fix: only use ordering or O(log n) when the problem promises it.
- Using the array layout for a sparse tree. A skewed tree of 30 nodes would need about a billion slots. Fix: use linked nodes unless the tree is complete.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Trees: words and shapes · 1/9
This lesson introduces trees: the words people use for them and the shapes you will meet in interviews.
Prefer a video by a teacher? Find free videos on “binary tree terminology root leaf height depth complete full perfect explained” on YouTube ↗
In real life: An org chart is a tree
A company's HR system stores who reports to whom. The CEO is the root, each manager is a parent of the people who report to them, and people with no reports are leaves. "How many levels of management are there?" is the height of the tree, and "how many people are in the technology team?" is the size of one subtree. Folder sizes on your laptop and nested categories on a shopping site are worked out the same way.
org = {
"CEO": ["CTO", "CFO"],
"CTO": ["Dev lead", "QA lead"],
"CFO": [],
"Dev lead": ["Intern"],
"QA lead": [],
"Intern": [],
}
def levels(person):
return 1 + max((levels(r) for r in org[person]), default=0)
print(levels("CEO"))Practice (0/4 done)
Write count_nodes(root) that returns the number of nodes in the binary tree. root is a TreeNode or None (an empty tree has 0 nodes). TreeNode and build(values) are already defined above your function. Example: count_nodes(build([1, 2, 3, 4, 5, None, 6])) returns 6.
Write max_depth(root) that returns the number of NODES on the longest path from the root down to a leaf. An empty tree returns 0 and a single node returns 1. Example: max_depth(build([3, 9, 20, None, None, 15, 7])) returns 3.
Write count_leaves(root) that returns how many leaves the tree has. A leaf is a node with NO children (both left and right are None). An empty tree has 0 leaves; a single node is 1 leaf. Example: count_leaves(build([1, 2, 3, 4, 5, None, 6])) returns 3.
A COMPLETE binary tree is stored in a list arr in heap layout (root at index 0, children of index i at 2i + 1 and 2i + 2, no gaps). Write array_leaves(arr) that returns the values of all leaves in index order. Use the layout rule: index i is a leaf when its left child index 2i + 1 is outside the list. Example: array_leaves([1, 2, 3, 4, 5]) returns [3, 4, 5].
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Traversals: DFS and BFSTrees and binary search trees · same module
- Recursive tree patternsTrees and binary search trees · same module
- Binary search treesTrees and binary search trees · same module
- Binary search treesC Programming (from zero to systems) · Data structures in C
- Heaps and priority queuesHeaps and greedy algorithms
- Tries (prefix trees)Tries, union-find and bit manipulation
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
A tree has 12 nodes. How many edges does it have?
Answer: 11
Every node except the root has exactly one edge to its parent, so n − 1 = 11.
Which statement about a complete binary tree is true?
Answer: Every level is full except maybe the last, which fills from the left
That is the definition of complete. The first is "full", the second "perfect", and the last is a BST rule.
In the array layout, the node at index 4 has its right child at which index?
Answer: 10
The right child is at 2i + 2 = 10; the left child is at 2i + 1 = 9.
Why is searching down one path O(log n) in a balanced tree but O(n) in a skewed one?
Answer: The cost is O(height), and the height is about log n when balanced but n − 1 when skewed
Walking down one path costs one step per level, and the number of levels is the height.
A tree is a single node. What is its height in edges, and its maximum depth counted in nodes?
Answer: 0 and 1
There are no edges, so height 0; the longest path has one node, so maximum depth 1.
What is the extra space of a recursive tree function on a balanced tree of n nodes?Related
Answer: O(log n)
The recursion stack holds one path from the root, and a balanced tree has height O(log n).
Which traversal frees a tree safely?Related
Deleting a node with two children: which value usually replaces it?Related
Answer: The smallest value in its right subtree (the inorder successor)
The successor is larger than everything on the left and smaller than everything else on the right, so the BST rule still holds.
From Binary search trees
Pop on a binary heap moves the last item to the root and then…Related
Answer: sifts it down, swapping with the smaller child while it is bigger
The moved item may be too big for the root, so it swaps downward with its smaller child until the heap property holds.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Trees and binary search trees” before its exam: Traversals: DFS and BFS, Recursive tree patterns, Binary search trees, Lowest common ancestor, serialisation and balanced trees.
- Module 7 exam: Trees and binary search trees · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Heaps and greedy algorithms. 61 topics left in the course before the final exam.