DSA course menu
Trees and Binary Trees: Terminology and Python Implementation
Learn the tree data structure: root, parent, child, leaf, depth and height, binary trees and their types, building a binary tree in Python, and computing size, height and leaf count recursively.
On this page
A tree stores data in a hierarchy: one item at the top branches into children, which branch into their own children, and so on. File systems, HTML pages, company org charts and the moves in a game are all trees.
CEO ← root
/ \
CTO CFO
/ \ \
Dev1 Dev2 Accountant ← leavesVocabulary#
A tree with n nodes always has exactly n − 1 edges, and there is exactly one path between any two nodes.
Binary trees#
In a binary tree, every node has at most two children, called left and right. It is the most important kind of tree in DSA.
class TreeNode:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
# 1
# / \
# 2 3
# / \ \
# 4 5 6
root = TreeNode(1,
TreeNode(2, TreeNode(4), TreeNode(5)),
TreeNode(3, None, TreeNode(6)))
print(root.value, root.left.value, root.right.right.value)1 2 6Thinking recursively about trees#
Every subtree is itself a tree, so most tree functions follow one recipe: handle the empty tree, then combine the answers for the left and right subtrees.
class TreeNode:
def __init__(self, value, left=None, right=None):
self.value, self.left, self.right = value, left, right
root = TreeNode(1,
TreeNode(2, TreeNode(4), TreeNode(5)),
TreeNode(3, None, TreeNode(6)))
def size(node):
if node is None:
return 0
return 1 + size(node.left) + size(node.right)
def height(node):
if node is None:
return -1 # so a single node has height 0
return 1 + max(height(node.left), height(node.right))
def count_leaves(node):
if node is None:
return 0
if node.left is None and node.right is None:
return 1
return count_leaves(node.left) + count_leaves(node.right)
def tree_sum(node):
return 0 if node is None else node.value + tree_sum(node.left) + tree_sum(node.right)
print("size", size(root))
print("height", height(root))
print("leaves", count_leaves(root))
print("sum", tree_sum(root))size 6
height 2
leaves 3
sum 21Each function visits every node once: O(n) time, and O(h) stack space for a tree of height h.
Types of binary trees#
- Full: every node has 0 or 2 children.
- Complete: every level is completely filled except possibly the last, which is filled from the left. Heaps are complete trees.
- Perfect: all internal nodes have 2 children and all leaves are at the same depth. A perfect tree of height h has 2^(h+1) − 1 nodes.
- Balanced: the heights of the left and right subtrees of every node differ by at most 1. Balanced trees have height O(log n).
- Degenerate: every node has one child, so the tree is really a linked list with height n − 1.
The height matters because most tree operations cost O(h). With a million nodes, a balanced tree is about 20 levels deep; a degenerate one is a million.
import math
for n in [7, 1_000, 1_000_000]:
print(f"{n:>9} nodes: balanced height ~{math.floor(math.log2(n))}, degenerate height {n - 1}") 7 nodes: balanced height ~2, degenerate height 6
1000 nodes: balanced height ~9, degenerate height 999
1000000 nodes: balanced height ~19, degenerate height 999999Common mistakes#
Practice#
Practice exercise
Write max_value(node) that returns the largest value in a binary tree (or None for an empty tree), and mirror(node) that swaps the left and right children of every node in place.
Show hint
max_value: compare the node's value with the maximum of each non-empty subtree. mirror: swap node.left and node.right, then mirror both subtrees.
Show solution
class TreeNode:
def __init__(self, value, left=None, right=None):
self.value, self.left, self.right = value, left, right
def max_value(node):
if node is None:
return None
best = node.value
for child in (node.left, node.right):
m = max_value(child)
if m is not None and m > best:
best = m
return best
def mirror(node):
if node is not None:
node.left, node.right = node.right, node.left
mirror(node.left)
mirror(node.right)
def show(node):
if node is None:
return "."
return f"({show(node.left)} {node.value} {show(node.right)})"
root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(9)), TreeNode(3))
print(max_value(root))
print(show(root))
mirror(root)
print(show(root))9
(((. 4 .) 2 (. 9 .)) 1 (. 3 .))
((. 3 .) 1 ((. 9 .) 2 (. 4 .)))Key takeaway#
Next: the different orders for visiting nodes, Tree Traversals.
Finished this lesson?
Related lessons
Recommended DSA resources
- Cracking the Coding Interview by Gayle Laakmann McDowell
189 practice questions with solutions, for coding interview preparation.
Some links are affiliate links. If you buy through them, Laviyx Learn may earn a commission at no extra cost to you. As an Amazon Associate, we earn from qualifying purchases.