Trees and terminology
On This Lesson 11 topics
Lesson Overview
So far the data structures in this course have been lines: arrays, lists, stacks, and queues. Each item has a place in a row. Many things in the real world are not rows. A company has a CEO, managers under the CEO, and staff under each manager. A folder on your computer holds files and other folders. A family tree has parents and children. All of these are trees.
This lesson gives you the vocabulary of trees (root, parent, child, leaf, subtree, height) and shows how a tree looks in Java code. It also introduces the binary tree, where each node has at most two children, which is the shape the rest of this module builds on.
Why this matters: a backend developer meets trees constantly: folder structures, category menus, comment threads, JSON documents, and the indexes that databases use to find rows quickly. If you cannot name the parts of a tree, you cannot read the documentation for any of them.
This lesson builds on recursion (the call stack module) and on writing small classes. It needs nothing else from this module.
Learning Objectives
By the end of this lesson you will be able to:
- Define a tree as nodes connected by links with no cycles.
- Name and point out the root, parents, children, leaves, and subtrees of a drawn tree.
- Compute the height of a tree, counting links, and explain why an empty tree is a special case.
- Define a binary tree and write a
Nodeclass withleftandrightreferences. - Explain why trees are naturally recursive and write a recursive method that visits every node.
- Tell a tree from a structure that is not a tree (one with a cycle).
Written Explanation
What a tree is
A tree is a set of nodes joined by links (also called edges). Two rules define it:
- There is exactly one starting node, the root, and every other node can be reached from it by exactly one path.
- There are no cycles: you can never follow links and arrive back where you started.
An organization chart is the classic picture. The CEO is the root. Each person has one boss (their parent) and may have people reporting to them (their children).
Trees are usually drawn upside down, with the root at the top and the branches growing downward. That is only a drawing convention.
The vocabulary
| Term | Meaning |
|---|---|
| Root | The top node. It has no parent. |
| Parent | A node that has nodes directly below it. |
| Child | A node directly below another node, joined by one link. |
| Siblings | Nodes that share the same parent. |
| Leaf | A node with no children. |
| Internal node | A node that is not a leaf. |
| Subtree | Any node together with everything below it. |
| Height | The number of links on the longest path from the root down to a leaf. |
Take this tree. The numbers are just labels inside the nodes.
8
/ \
3 10
/ \
1 6- The root is 8.
- 3 is the parent of 1 and 6; 1 and 6 are siblings.
- The leaves are 1, 6, and 10. The internal nodes are 8 and 3.
- The subtree rooted at 3 is the node 3 with 1 and 6 below it.
- The longest path is 8 to 3 to 1 (two links), so the height is 2.
Height counts links, not nodes. A tree with one node has height 0. Some books count nodes instead, so check which convention is in use. In this module, height means links.
Binary trees
A tree can have any number of children per node. A binary tree limits each node to at most two children, called the left child and the right child. Each side may also be empty. The drawing above is a binary tree.
In Java, a binary tree node needs a value and two references:
public class Node {
int value;
Node left;
Node right;
Node(int value) {
this.value = value;
}
boolean isLeaf() {
return left == null && right == null;
}
}A missing child is stored as null. A node is a leaf when both references are null. A reference to a whole tree is just a reference to its root node, and null stands for the empty tree.
Trees are recursive
Look again at the node 3 in the drawing: it is itself the root of a smaller tree. Every node is the root of its own subtree, and each subtree has the same shape as the whole. A binary tree is either empty, or a root with a left subtree and a right subtree, each of which is again a binary tree.
This is the same self-similar idea you used in recursion: solve the problem for the whole tree by solving it for the two subtrees, then combine the answers. The base case is the empty tree (null). Here is the height:
static int height(Node n) {
if (n == null) return -1;
return 1 + Math.max(height(n.left), height(n.right));
}The base case returns -1 so that a single node, whose two children are null, gets 1 + max(-1, -1) = 0. This matches the counting-links convention. Most tree methods you will write look like this: if the node is null, return a base answer; otherwise combine the answers from the left and right subtrees.
Not every structure is a tree
If a node can be reached by two different paths, or a link leads back up to an ancestor, the structure is a graph, not a tree. A road map is a graph. Graphs get their own module later in the course.
Examples
Example 1: reading a tree by hand (simple)
Using the tree above, answer four questions:
- Which node is the parent of 6? Node 3.
- How many children does 10 have? None, so it is a leaf.
- Is 8 a leaf? No. It has two children.
- What is the height of the subtree rooted at 3? One, because the longest path from 3 goes down one link (to 1 or to 6).
Notice that the height of a subtree depends on which node you call the root. The whole tree has height 2, and the subtree at 3 has height 1.
Example 2: an org chart with more than two children (practical)
A binary tree is a special case. An org chart can give a manager three reports, so a Node with left and right is not enough. A general tree stores a list of children.
import java.util.ArrayList;
import java.util.List;
public class Org {
static class Person {
String name;
List<Person> reports = new ArrayList<>();
Person(String name) { this.name = name; }
}
static int height(Person p) {
int best = 0;
for (Person r : p.reports) {
best = Math.max(best, 1 + height(r));
}
return best;
}
static void print(Person p, int depth) {
System.out.println(" ".repeat(depth) + p.name);
for (Person r : p.reports) print(r, depth + 1);
}
public static void main(String[] args) {
Person ceo = new Person("Dana (CEO)");
Person cto = new Person("Omar (CTO)");
Person cfo = new Person("Lina (CFO)");
ceo.reports.add(cto);
ceo.reports.add(cfo);
cto.reports.add(new Person("Sam"));
cto.reports.add(new Person("Noor"));
cto.reports.add(new Person("Yusuf"));
print(ceo, 0);
System.out.println("height = " + height(ceo));
}
}Output (compiled and run with JDK 21):
Dana (CEO)
Omar (CTO)
Sam
Noor
Yusuf
Lina (CFO)
height = 2A person with no reports is a leaf, and the for loop simply does nothing, so the recursion stops without a null check. From here on we use binary trees, because the two-child rule keeps the algorithms simple.
Example 3: measuring a binary tree in code (realistic)
We build the tree from the drawing by hand and measure it with three recursive methods in a Demo class that uses the Node class shown earlier.
public class Demo {
static int height(Node n) {
if (n == null) return -1;
return 1 + Math.max(height(n.left), height(n.right));
}
static int size(Node n) {
if (n == null) return 0;
return 1 + size(n.left) + size(n.right);
}
static int countLeaves(Node n) {
if (n == null) return 0;
if (n.isLeaf()) return 1;
return countLeaves(n.left) + countLeaves(n.right);
}
public static void main(String[] args) {
Node root = new Node(8);
root.left = new Node(3);
root.right = new Node(10);
root.left.left = new Node(1);
root.left.right = new Node(6);
System.out.println("size = " + size(root));
System.out.println("height = " + height(root));
System.out.println("leaves = " + countLeaves(root));
System.out.println("height of node 3 = " + height(root.left));
System.out.println("is 10 a leaf? " + root.right.isLeaf());
}
}Output (compiled and run with JDK 21):
size = 5
height = 2
leaves = 3
height of node 3 = 1
is 10 a leaf? trueAll three methods follow the same pattern: handle null first, then combine the results from n.left and n.right. Each of them visits every node exactly once, so each takes time proportional to the number of nodes.
Backend Insight
Trees appear all over backend work, usually without being called trees:
- File systems and URLs. Folders contain folders. A path such as
/orders/2024/marchwalks down a tree. - JSON and XML documents. An object contains objects and arrays that contain objects. When a service parses a request body, it builds a tree in memory.
- Categories and comments. A product category with subcategories, or a comment thread with replies, is stored as a tree in a database table in which each row points to its parent.
- Database indexes. A database finds a row by key without reading every row by walking down a tree built for the purpose. A later module (MID-012) looks at the B-tree, which is a tree with many children per node.
The recursive habit from this lesson is how code processes all of these: handle one node and delegate the rest to its children. It carries one risk: very deep trees mean deep recursion, and every call uses a stack frame. Lesson 4 returns to this.
Common Mistakes
Mistake 1: Forgetting the null check
static int size(Node n) {
return 1 + size(n.left) + size(n.right); // wrong: no base case
}Every leaf has null children, so the recursion eventually calls size(null) and reads n.left on null. That throws a NullPointerException. Always write if (n == null) first.
Mistake 2: Mixing up height and number of nodes
The tree in this lesson has 5 nodes and height 2. Height measures the longest path, not the count. A tree with 1,000 nodes can have a height of 9 or a height of 999, depending on its shape. That difference is the whole subject of Lesson 4.
Mistake 3: Counting nodes instead of links for height
A single node has height 0, not 1 (in this course). If you return 0 for null in height, a single node gets height 1 and every answer is off by one. Choose one convention and keep it.
Exercises
Try each exercise yourself before opening the solutions.
Use this tree for A1 to A3 and for B1: root 20 with children 12 and 30; node 12 has children 5 and 15; node 30 has only a right child, 40.
Level A: Foundation
A1. Name the root, the leaves, and the parent of 15.
Show solution A1
A1. The root is 20. The leaves are 5, 15, and 40. The parent of 15 is 12.
A2. What is the height of the tree, and what is the height of the subtree rooted at 30?
Show solution A2
A2. The longest path is 20 to 12 to 5 (or to 15), which is 2 links, so the height is 2. The subtree rooted at 30 has the path 30 to 40, so its height is 1.
A3. What is the largest number of nodes a binary tree of height 2 can have?
Show solution A3
A3. 7 nodes: one root, two children, and four grandchildren (1 + 2 + 4).
Level B: Application
B1. Assume the Node class from this lesson and root refers to the tree above. Write the Java statements that build it.
Show solution B1
B1.
Node root = new Node(20);
root.left = new Node(12);
root.right = new Node(30);
root.left.left = new Node(5);
root.left.right = new Node(15);
root.right.right = new Node(40);B2. Write static int sumValues(Node n) that returns the sum of all values in a binary tree. What does it return for an empty tree?
Show solution B2
B2.
static int sumValues(Node n) {
if (n == null) return 0;
return n.value + sumValues(n.left) + sumValues(n.right);
}An empty tree returns 0, the neutral value for addition. For the tree above, the result is 122 (compiled and run with JDK 21).
B3. A file system has a folder docs that holds a.txt and a folder old; old holds b.txt. Draw it as a tree. Which items are leaves? Is docs a leaf?
Show solution B3
B3. docs is the root. Its children are a.txt and old. old has one child, b.txt. The leaves are a.txt and b.txt. docs is not a leaf because it has children, and neither is old, because it holds b.txt. (An empty folder would be a leaf.)
Level C: Challenge
C1. Write static int maxValue(Node n) that returns the largest value in a binary tree (the values are not sorted). Choose a sensible result for an empty tree and explain your choice.
Show solution C1
C1.
static int maxValue(Node n) {
if (n == null) return Integer.MIN_VALUE;
return Math.max(n.value, Math.max(maxValue(n.left), maxValue(n.right)));
}Integer.MIN_VALUE is a safe answer for an empty tree because any real value is greater than or equal to it, so it never wins the max. For the tree above, the result is 40.
C2. A binary tree has 15 nodes. What is the smallest height it can have, and what is the largest? Explain in one or two sentences.
Show solution C2
C2. The smallest height is 3: heights 0, 1, 2 hold at most 1, 3, and 7 nodes in total, which is fewer than 15, while height 3 allows up to 15. The largest height is 14: if every node has just one child, the tree is a chain of 15 nodes with 14 links.
Mini Challenge
Choose a tree you already know: a folder on your computer, a family, a menu on a website, or the org chart of a team. Write it down as an indented list, as the print method in Example 2 does. Then answer:
- Which node is the root, and which nodes are leaves?
- What is its height, counting links?
- Is it a binary tree? If not, what is the largest number of children any node has?
Check your work: the root has no parent, every other node has exactly one, and no node appears twice.
Summary & Next Lesson
Key takeaways
- A tree is nodes joined by links with one root, one path to every node, and no cycles.
- The vocabulary: root, parent, child, sibling, leaf, subtree, height.
- Height counts the links on the longest root-to-leaf path. A single node has height 0 and the empty tree is -1 in our code.
- A binary tree gives every node at most two children,
leftandright, withnullfor a missing child. - Trees are recursive: handle
null, then combine the answers from the two subtrees.
Next lesson
The next lesson, "Binary search trees", adds one ordering rule to a binary tree: smaller values go left and larger values go right. That rule lets you search by throwing away half of the remaining tree at every step.
Self-check
- What are the two rules that make a structure a tree?
- In a binary tree, how many children can a node have at most?
- What is the height of a tree that has only a root node?
- What should a recursive tree method return or do when it receives
null? - A node can be reached by two different paths. Is the structure a tree?
Show answers
- One root with exactly one path to every other node, and no cycles.
- Two: a left child and a right child.
- 0, when height counts links.
- It should return a base answer (0 for a count, -1 for height in our convention) and stop recursing, so it never reads a field of
null. - No. Two paths mean it has a shared node or a cycle, which makes it a graph.
References
- NIST Dictionary of Algorithms and Data Structures: binary tree. It defines a binary tree as a tree where each node has at most two children, and as either empty or a root with a left and a right binary tree.
- OpenDSA (Virginia Tech): Binary Tree Implementations. It shows nodes with
leftandrightchild references and a leaf defined as a node with bothnull. It does not give formal definitions of root, height, or subtree, so those definitions here are the common textbook ones; the course counts height in links, and other books count nodes. - Every Java example above was compiled and run with JDK 21 and the output is copied from the real run.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.