Trees and binary trees
Learn the vocabulary of trees (root, parent, child, leaf, depth, height, subtree), build a general tree in C#, and meet binary trees and why their height matters.
The vocabulary
| Term | Meaning |
|---|---|
A general tree in C#
var project = new TreeNode("Project");var a = project.Add("Building A");var a1 = a.Add("Level 1");a1.Add("C1");a1.Add("C2");a.Add("Level 2").Add("C3");project.Add("Building B").Add("Level 1").Add("B1"); Print(project, 0);Console.WriteLine($"Nodes: {Count(project)}, height: {Height(project)}"); static void Print(TreeNode node, int depth){ Console.WriteLine(new string(' ', depth * 2) + node.Name); // indent by depth foreach (var child in node.Children) Print(child, depth + 1);} static int Count(TreeNode node) => 1 + node.Children.Sum(c => Count(c)); static int Height(TreeNode node) => node.Children.Count == 0 ? 0 : 1 + node.Children.Max(c => Height(c)); class TreeNode{ public string Name { get; } public List<TreeNode> Children { get; } = new(); public TreeNode(string name) => Name = name; public TreeNode Add(string name) { var child = new TreeNode(name); Children.Add(child); return child; // so calls can be chained }}Project
Building A
Level 1
C1
C2
Level 2
C3
Building B
Level 1
B1
Nodes: 10, height: 3System.IO.Directory (folders), XML and JSON documents (XElement, JsonNode), the HTML DOM, menus, an organisation chart, and Revit or Tekla model hierarchies.
Binary trees
// 8// / \// 4 12// / \// 2 6var root = new Node(8, new Node(4, new Node(2), new Node(6)), new Node(12)); Console.WriteLine(root.Left!.Right!.Value); // 8 → left → right record Node(int Value, Node? Left = null, Node? Right = null);6
Why height is the number to watch
Perfect / complete (every level full, or full except the last, filled from the left): height ≈ log₂ n. A million nodes fit in about 20 levels. Degenerate (every node has one child): it is really a linked list, height n − 1. Walking it is O(n).
| Height h | Most nodes a binary tree can hold (2ʰ⁺¹ − 1) |
|---|---|
TreeNode class above, write Leaves(TreeNode node) that counts the leaves, and Find(TreeNode node, string name) that returns the first node with that name (or null), searching depth first. For the Project tree: 4 leaves, and Find(project, "C3") returns the node named C3.
Show a hint
Show the solution
var project = new TreeNode("Project");var a = project.Add("Building A");var a1 = a.Add("Level 1");a1.Add("C1");a1.Add("C2");a.Add("Level 2").Add("C3");project.Add("Building B").Add("Level 1").Add("B1"); Console.WriteLine(Leaves(project));Console.WriteLine(Find(project, "C3")?.Name ?? "not found");Console.WriteLine(Find(project, "C9")?.Name ?? "not found"); static int Leaves(TreeNode node) => node.Children.Count == 0 ? 1 : node.Children.Sum(c => Leaves(c)); static TreeNode? Find(TreeNode node, string name){ if (node.Name == name) return node; foreach (var child in node.Children) { var hit = Find(child, name); if (hit is not null) return hit; } return null;} class TreeNode{ public string Name { get; } public List<TreeNode> Children { get; } = new(); public TreeNode(string name) => Name = name; public TreeNode Add(string name) { var c = new TreeNode(name); Children.Add(c); return c; }}4 C3 not found
Remember
A tree is a hierarchy: one root, every other node has exactly one parent, no loops, n − 1 edges. Depth counts edges from the root; height counts edges down to the deepest leaf. Tree code is naturally recursive: do the node, then recurse into the children. Operations cost O(height): about log₂ n for a balanced binary tree, n for a degenerate one.