0
0
DSA Goprogramming

Build Heap from Array Heapify in DSA Go

Choose your learning style9 modes available
Mental Model
We turn an unordered list into a heap by fixing each subtree from the bottom up, ensuring the heap property holds everywhere.
Analogy: Imagine organizing a pyramid of boxes where each box must be heavier than the boxes above it. You start fixing from the bottom rows up to the top, swapping boxes to keep the pyramid stable.
Array: [4, 10, 3, 5, 1]
Index:  0   1   2   3   4
Heap tree:
       4
     /   \
   10     3
  /  \
 5    1
Dry Run Walkthrough
Input: array: [4, 10, 3, 5, 1]
Goal: Convert the array into a max heap where each parent is greater than its children
Step 1: Start heapify at index 1 (value 10), check children at indices 3 and 4
[4, 10, 3, 5, 1]
Heap tree:
       4
     /   \
   10     3
  /  \
 5    1
Why: We start from the last non-leaf node to fix subtrees bottom-up
Step 2: Compare 10 with children 5 and 1, no swap needed as 10 is largest
[4, 10, 3, 5, 1]
Heap tree:
       4
     /   \
   10     3
  /  \
 5    1
Why: Subtree rooted at index 1 already satisfies max heap property
Step 3: Heapify at index 0 (value 4), compare with children 10 and 3
[4, 10, 3, 5, 1]
Heap tree:
       4
     /   \
   10     3
  /  \
 5    1
Why: Fix the root subtree to maintain heap property
Step 4: Swap 4 with largest child 10 at index 1
[10, 4, 3, 5, 1]
Heap tree:
      10
     /   \
    4     3
  /  \
 5    1
Why: Parent must be larger than children, so swap with largest child
Step 5: Heapify at index 1 (value 4), compare with children 5 and 1
[10, 4, 3, 5, 1]
Heap tree:
      10
     /   \
    4     3
  /  \
 5    1
Why: After swap, fix subtree rooted at index 1
Step 6: Swap 4 with largest child 5 at index 3
[10, 5, 3, 4, 1]
Heap tree:
      10
     /   \
    5     3
  /  \
 4    1
Why: Maintain max heap property by swapping with largest child
Step 7: Heapify at index 3 (value 4), no children to compare, stop
[10, 5, 3, 4, 1]
Heap tree:
      10
     /   \
    5     3
  /  \
 4    1
Why: Leaf node reached, heapify complete
Result:
[10, 5, 3, 4, 1]
Heap tree:
      10
     /   \
    5     3
  /  \
 4    1
Annotated Code
DSA Go
package main

import "fmt"

// Heapify fixes the subtree rooted at index i in array arr of size n
func heapify(arr []int, n int, i int) {
    largest := i
    left := 2*i + 1
    right := 2*i + 2

    // If left child exists and is greater than root
    if left < n && arr[left] > arr[largest] {
        largest = left
    }

    // If right child exists and is greater than current largest
    if right < n && arr[right] > arr[largest] {
        largest = right
    }

    // If largest is not root
    if largest != i {
        arr[i], arr[largest] = arr[largest], arr[i] // swap
        heapify(arr, n, largest) // recursively heapify affected subtree
    }
}

// buildHeap converts array into a max heap
func buildHeap(arr []int) {
    n := len(arr)
    // Start from last non-leaf node and heapify each
    for i := n/2 - 1; i >= 0; i-- {
        heapify(arr, n, i)
    }
}

func main() {
    arr := []int{4, 10, 3, 5, 1}
    buildHeap(arr)
    // Print heap as array
    for i, v := range arr {
        if i > 0 {
            fmt.Print(" -> ")
        }
        fmt.Print(v)
    }
    fmt.Println(" -> null")
}
if left < n && arr[left] > arr[largest] {
Check if left child is larger than current largest
if right < n && arr[right] > arr[largest] {
Check if right child is larger than current largest
if largest != i {
If root is not largest, swap and heapify subtree
for i := n/2 - 1; i >= 0; i-- {
Start heapify from last non-leaf node up to root
OutputSuccess
10 -> 5 -> 3 -> 4 -> 1 -> null
Complexity Analysis
Time: O(n) because heapify is called on n/2 nodes and each call takes O(log n) in worst case, but overall buildHeap runs in linear time
Space: O(log n) due to recursion stack in heapify calls
vs Alternative: Naive approach inserting elements one by one into heap takes O(n log n), so buildHeap is more efficient
Edge Cases
empty array
No operations performed, heap remains empty
DSA Go
for i := n/2 - 1; i >= 0; i-- {
array with one element
Heapify called once but no swaps needed, array remains same
DSA Go
for i := n/2 - 1; i >= 0; i-- {
array with all equal elements
No swaps needed, heap property already holds
DSA Go
if largest != i {
When to Use This Pattern
When you need to build a heap from an unordered array efficiently, use the bottom-up heapify approach starting from the last non-leaf node.
Common Mistakes
Mistake: Starting heapify from index 0 instead of last non-leaf node
Fix: Start from index n/2 - 1 and move backwards to root
Mistake: Not recursively heapifying after swap
Fix: Call heapify recursively on the affected child index after swapping
Summary
Build Heap from Array Heapify converts an unordered array into a max heap by fixing subtrees from bottom up.
Use it when you want to efficiently create a heap from a list of elements.
The key insight is starting heapify from the last non-leaf node and moving upwards ensures all subtrees satisfy heap property.