Binary Tree

A binary tree is a tree data structure where each node has at most two children, referred to as the left child and right child.

Structure

 1type TreeNode struct {
 2    Val   int
 3    Left  *TreeNode
 4    Right *TreeNode
 5}
 6
 7// Helper to create a node
 8func NewNode(val int) *TreeNode {
 9    return &TreeNode{Val: val}
10}

Visualization

Types of Binary Trees

1. Full Binary Tree

Every node has either 0 or 2 children.

Properties:

  • If height is $h$, maximum nodes: $2^{h+1} - 1$
  • If $n$ is total nodes, $i$ is internal nodes, $l$ is leaves: $n = 2i + 1$ and $l = i + 1$

2. Complete Binary Tree

All levels completely filled except possibly the last level, filled from left to right.

Properties:

  • Height: $h = \lfloor \log_2 n \rfloor$
  • Used in heap implementation

3. Perfect Binary Tree

All internal nodes have exactly 2 children, all leaves at same level.

Properties:

  • Total nodes: $n = 2^{h+1} - 1$
  • Leaves: $2^h$
  • Internal nodes: $2^h - 1$

4. Balanced Binary Tree

Height of left and right subtrees differ by at most 1.

Balance Factor: $$ BF = \text{height}(\text{left}) - \text{height}(\text{right}) $$

Balanced if: $|BF| \leq 1$ for all nodes

 1func IsBalanced(root *TreeNode) bool {
 2    _, balanced := checkHeight(root)
 3    return balanced
 4}
 5
 6func checkHeight(node *TreeNode) (int, bool) {
 7    if node == nil {
 8        return 0, true
 9    }
10    
11    leftHeight, leftBalanced := checkHeight(node.Left)
12    if !leftBalanced {
13        return 0, false
14    }
15    
16    rightHeight, rightBalanced := checkHeight(node.Right)
17    if !rightBalanced {
18        return 0, false
19    }
20    
21    if abs(leftHeight - rightHeight) > 1 {
22        return 0, false
23    }
24    
25    return 1 + max(leftHeight, rightHeight), true
26}
27
28func abs(x int) int {
29    if x < 0 {
30        return -x
31    }
32    return x
33}

Tree Traversals

In-Order (Left → Root → Right)

 1func InOrder(root *TreeNode) []int {
 2    result := []int{}
 3    inOrderHelper(root, &result)
 4    return result
 5}
 6
 7func inOrderHelper(node *TreeNode, result *[]int) {
 8    if node == nil {
 9        return
10    }
11    
12    inOrderHelper(node.Left, result)
13    *result = append(*result, node.Val)
14    inOrderHelper(node.Right, result)
15}
16
17// Iterative version
18func InOrderIterative(root *TreeNode) []int {
19    result := []int{}
20    stack := []*TreeNode{}
21    curr := root
22    
23    for curr != nil || len(stack) > 0 {
24        // Go to leftmost node
25        for curr != nil {
26            stack = append(stack, curr)
27            curr = curr.Left
28        }
29        
30        // Process node
31        curr = stack[len(stack)-1]
32        stack = stack[:len(stack)-1]
33        result = append(result, curr.Val)
34        
35        // Go to right subtree
36        curr = curr.Right
37    }
38    
39    return result
40}

Use case: For BST, produces sorted sequence

Time: $O(n)$, Space: $O(h)$ where $h$ is height

Pre-Order (Root → Left → Right)

 1func PreOrder(root *TreeNode) []int {
 2    result := []int{}
 3    preOrderHelper(root, &result)
 4    return result
 5}
 6
 7func preOrderHelper(node *TreeNode, result *[]int) {
 8    if node == nil {
 9        return
10    }
11    
12    *result = append(*result, node.Val)
13    preOrderHelper(node.Left, result)
14    preOrderHelper(node.Right, result)
15}
16
17// Iterative version
18func PreOrderIterative(root *TreeNode) []int {
19    if root == nil {
20        return []int{}
21    }
22    
23    result := []int{}
24    stack := []*TreeNode{root}
25    
26    for len(stack) > 0 {
27        node := stack[len(stack)-1]
28        stack = stack[:len(stack)-1]
29        
30        result = append(result, node.Val)
31        
32        // Push right first (so left is processed first)
33        if node.Right != nil {
34            stack = append(stack, node.Right)
35        }
36        if node.Left != nil {
37            stack = append(stack, node.Left)
38        }
39    }
40    
41    return result
42}

Use case: Create copy of tree, prefix expression

Post-Order (Left → Right → Root)

 1func PostOrder(root *TreeNode) []int {
 2    result := []int{}
 3    postOrderHelper(root, &result)
 4    return result
 5}
 6
 7func postOrderHelper(node *TreeNode, result *[]int) {
 8    if node == nil {
 9        return
10    }
11    
12    postOrderHelper(node.Left, result)
13    postOrderHelper(node.Right, result)
14    *result = append(*result, node.Val)
15}

Use case: Delete tree, postfix expression, calculate directory sizes

Level-Order (BFS)

 1func LevelOrder(root *TreeNode) [][]int {
 2    if root == nil {
 3        return [][]int{}
 4    }
 5    
 6    result := [][]int{}
 7    queue := []*TreeNode{root}
 8    
 9    for len(queue) > 0 {
10        levelSize := len(queue)
11        level := []int{}
12        
13        for i := 0; i < levelSize; i++ {
14            node := queue[0]
15            queue = queue[1:]
16            
17            level = append(level, node.Val)
18            
19            if node.Left != nil {
20                queue = append(queue, node.Left)
21            }
22            if node.Right != nil {
23                queue = append(queue, node.Right)
24            }
25        }
26        
27        result = append(result, level)
28    }
29    
30    return result
31}

Time: $O(n)$, Space: $O(w)$ where $w$ is maximum width

Common Operations

1. Height Calculation

1func Height(root *TreeNode) int {
2    if root == nil {
3        return -1 // or 0 depending on definition
4    }
5    
6    return 1 + max(Height(root.Left), Height(root.Right))
7}

Time: $O(n)$

2. Count Nodes

1func CountNodes(root *TreeNode) int {
2    if root == nil {
3        return 0
4    }
5    
6    return 1 + CountNodes(root.Left) + CountNodes(root.Right)
7}

Time: $O(n)$

3. Diameter (Longest Path)

 1func DiameterOfBinaryTree(root *TreeNode) int {
 2    diameter := 0
 3    calculateHeight(root, &diameter)
 4    return diameter
 5}
 6
 7func calculateHeight(node *TreeNode, diameter *int) int {
 8    if node == nil {
 9        return 0
10    }
11    
12    leftHeight := calculateHeight(node.Left, diameter)
13    rightHeight := calculateHeight(node.Right, diameter)
14    
15    // Update diameter if path through this node is longer
16    *diameter = max(*diameter, leftHeight + rightHeight)
17    
18    return 1 + max(leftHeight, rightHeight)
19}

Time: $O(n)$

4. Lowest Common Ancestor

 1func LowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
 2    if root == nil || root == p || root == q {
 3        return root
 4    }
 5    
 6    left := LowestCommonAncestor(root.Left, p, q)
 7    right := LowestCommonAncestor(root.Right, p, q)
 8    
 9    if left != nil && right != nil {
10        return root // Both found in different subtrees
11    }
12    
13    if left != nil {
14        return left
15    }
16    return right
17}

Time: $O(n)$

5. Maximum Path Sum

 1func MaxPathSum(root *TreeNode) int {
 2    maxSum := root.Val
 3    maxPathSumHelper(root, &maxSum)
 4    return maxSum
 5}
 6
 7func maxPathSumHelper(node *TreeNode, maxSum *int) int {
 8    if node == nil {
 9        return 0
10    }
11    
12    // Get max sum from left and right (ignore negative paths)
13    leftMax := max(0, maxPathSumHelper(node.Left, maxSum))
14    rightMax := max(0, maxPathSumHelper(node.Right, maxSum))
15    
16    // Max path through this node
17    pathThroughNode := node.Val + leftMax + rightMax
18    *maxSum = max(*maxSum, pathThroughNode)
19    
20    // Return max path extending from this node
21    return node.Val + max(leftMax, rightMax)
22}

Time: $O(n)$

6. Serialize and Deserialize

 1import "strconv"
 2import "strings"
 3
 4func Serialize(root *TreeNode) string {
 5    if root == nil {
 6        return "null"
 7    }
 8    
 9    return strconv.Itoa(root.Val) + "," + 
10           Serialize(root.Left) + "," + 
11           Serialize(root.Right)
12}
13
14func Deserialize(data string) *TreeNode {
15    values := strings.Split(data, ",")
16    index := 0
17    return deserializeHelper(&values, &index)
18}
19
20func deserializeHelper(values *[]string, index *int) *TreeNode {
21    if *index >= len(*values) || (*values)[*index] == "null" {
22        *index++
23        return nil
24    }
25    
26    val, _ := strconv.Atoi((*values)[*index])
27    *index++
28    
29    node := &TreeNode{Val: val}
30    node.Left = deserializeHelper(values, index)
31    node.Right = deserializeHelper(values, index)
32    
33    return node
34}

Time: $O(n)$

7. Invert Tree (Mirror)

 1func InvertTree(root *TreeNode) *TreeNode {
 2    if root == nil {
 3        return nil
 4    }
 5    
 6    // Swap children
 7    root.Left, root.Right = root.Right, root.Left
 8    
 9    // Recursively invert subtrees
10    InvertTree(root.Left)
11    InvertTree(root.Right)
12    
13    return root
14}

Time: $O(n)$

Binary Search Tree (BST)

A binary tree where for each node:

  • All values in left subtree < node value
  • All values in right subtree > node value

BST Operations

 1// Insert
 2func Insert(root *TreeNode, val int) *TreeNode {
 3    if root == nil {
 4        return &TreeNode{Val: val}
 5    }
 6    
 7    if val < root.Val {
 8        root.Left = Insert(root.Left, val)
 9    } else {
10        root.Right = Insert(root.Right, val)
11    }
12    
13    return root
14}
15
16// Search
17func Search(root *TreeNode, val int) *TreeNode {
18    if root == nil || root.Val == val {
19        return root
20    }
21    
22    if val < root.Val {
23        return Search(root.Left, val)
24    }
25    return Search(root.Right, val)
26}
27
28// Delete
29func DeleteNode(root *TreeNode, key int) *TreeNode {
30    if root == nil {
31        return nil
32    }
33    
34    if key < root.Val {
35        root.Left = DeleteNode(root.Left, key)
36    } else if key > root.Val {
37        root.Right = DeleteNode(root.Right, key)
38    } else {
39        // Node to delete found
40        if root.Left == nil {
41            return root.Right
42        }
43        if root.Right == nil {
44            return root.Left
45        }
46        
47        // Node has two children: get inorder successor
48        minNode := findMin(root.Right)
49        root.Val = minNode.Val
50        root.Right = DeleteNode(root.Right, minNode.Val)
51    }
52    
53    return root
54}
55
56func findMin(node *TreeNode) *TreeNode {
57    for node.Left != nil {
58        node = node.Left
59    }
60    return node
61}
62
63// Validate BST
64func IsValidBST(root *TreeNode) bool {
65    return isValidBSTHelper(root, nil, nil)
66}
67
68func isValidBSTHelper(node *TreeNode, min, max *int) bool {
69    if node == nil {
70        return true
71    }
72    
73    if (min != nil && node.Val <= *min) || (max != nil && node.Val >= *max) {
74        return false
75    }
76    
77    return isValidBSTHelper(node.Left, min, &node.Val) &&
78           isValidBSTHelper(node.Right, &node.Val, max)
79}

BST Time Complexity:

  • Search/Insert/Delete: $O(h)$ where $h$ is height
  • Best case (balanced): $O(\log n)$
  • Worst case (skewed): $O(n)$

Complexity Summary

OperationTimeSpace
Traversal$O(n)$$O(h)$
Height$O(n)$$O(h)$
Count Nodes$O(n)$$O(h)$
Search (general)$O(n)$$O(h)$
Search (BST)$O(h)$$O(h)$
Insert (BST)$O(h)$$O(h)$
Delete (BST)$O(h)$$O(h)$

where $h$ is height: $O(\log n)$ for balanced, $O(n)$ for skewed

Helper Functions

 1func max(a, b int) int {
 2    if a > b {
 3        return a
 4    }
 5    return b
 6}
 7
 8func min(a, b int) int {
 9    if a < b {
10        return a
11    }
12    return b
13}

Related Snippets

  • Binary Search
    Binary search is an efficient algorithm for finding a target value in a sorted …
  • General Tree
    A tree is a hierarchical data structure consisting of nodes connected by edges, …
  • Heap Data Structure
    A heap is a specialized tree-based data structure that satisfies the heap …
  • Heap Sort
    Heap sort is a comparison-based sorting algorithm that uses a binary heap data …
  • Linked List Operations
    Optimal techniques for common linked list operations using pointer manipulation, …
  • LRU and LFU Cache
    Cache replacement policies determine which items to evict when the cache is …
  • Merge Sort
    Merge sort is a stable, comparison-based sorting algorithm that uses the …
  • Quadtree
    A Quadtree is a tree data structure where each internal node has exactly four …
  • Quick Sort
    Quick sort is an efficient, in-place, comparison-based sorting algorithm that …
  • String Similarity Algorithms
    Algorithms for measuring similarity between strings, used in spell checking, DNA …
  • Terrain & Heightmap Generation
    Procedural terrain generation creates realistic landscapes using mathematical …
  • Trie (Prefix Tree)
    A Trie (pronounced &quot;try&quot;) is a tree-like data structure used to store …
  • Wave Function Collapse
    Wave Function Collapse (WFC) is a procedural generation algorithm that creates …