Lecture 12 Heap Sort

Joseph Haugh

University of New Mexico

Review Quiz

What does this code print with array = {4,2,6,7,1,3,5}?

void foo(int array[], int n) { 
  int i, swap = 1;
  while(swap) { 
    swap = 0;
    for (i = 0; i < n - 1; i++) {
      if (array[i] <= array[i+1]) { 
        printf("Swap: array[%d]=%d with array[%d]=%d\n", 
               i, array[i], i+1, array[i+1]);
        int tmp = array[i];
        array[i] = array[i+1];
        array[i+1] = tmp;
        swap = 1;
      }}}}

Review Quiz

Swap: array[1]=2 with array[2]=6
Swap: array[2]=2 with array[3]=7
Swap: array[4]=1 with array[5]=3
Swap: array[5]=1 with array[6]=5
Swap: array[0]=4 with array[1]=6
Swap: array[1]=4 with array[2]=7
Swap: array[3]=2 with array[4]=3
Swap: array[4]=2 with array[5]=5
Swap: array[0]=6 with array[1]=7
Swap: array[3]=3 with array[4]=5
Swap: array[2]=4 with array[3]=5

Heap Sort Algorithm

  • Make a heap
  • While heap is not empty
    • Remove the largest item
    • Restore heap property

So what is a heap then?

Heap

  • A binary tree with the following properties:
    • Complete: all levels are filled except possibly the last, which is filled left to right
    • Heap property: parent child
    • Largest value is at the root
    • Subtrees are also heaps

Complete Binary Tree as Array

We can represent a complete binary tree as an array.

  • Root is at index 0
  • For a node at index i
    • Left child is at index 2i + 1
    • Right child is at index 2i + 2

Example

{ x, s, m, p, c, l, k, e, a }

        x
       / \
      s   m
     / \ / \
    p  c l  k
   / \
  e   a

What if l had children and c did not?

Wouldn’t we have empty spaces in the array?

This is why the heap is filled left to right!

Heapsort: heapsort

void heapsort(char a[], int n) {
  int end;
  heapify(a, n);
  for(end = n - 1; end > 0; end--) {
    printf(" Sorting: %s, end=%d\n", a, end);
    swap(a, 0, end);
    siftDown(a, 0, end);
  }
}

Heapsort: Swap

void swap(char a[], int i, int j) {
  char tmp = a[i];
  a[i] = a[j];
  a[j] = tmp;
}

Heapsort: Heapify

void heapify(char a[], int n) {
  int i;
  /* Parent of n is (n-2)/2 */
  for(i = (n - 2) / 2; i >= 0; i--) {
    siftDown(a, i, n);
  }
}

Heapsort: Sift Down

void siftDown(char a[], int i, int n) {
  int left = 2*i+1;
  int right = 2*i+2;
  int largest = i;
  /* Is a child larger than this node? */
  if(left < n && a[left] > a[largest]) { 
    largest = left;
  }
  if(right < n && a[right] > a[largest]) { 
    largest = right;
  }
  /* if child is larger, swap and fix subtree */
  if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
  }}

Heapsort: Main

void main(void) {
  char data[] = "CELKMSPXA";
  
  printf("Original: %s\n", data);
  heapsort(data, 9);
  printf("  Sorted: %s\n", data);
} 

Heapsort: Output

Original: CELKMSPXA
 Sorting: XMSKCLPEA, end=8
 Sorting: SMPKCLAEX, end=7
 Sorting: PMLKCEASX, end=6
 Sorting: MKLACEPSX, end=5
 Sorting: LKEACMPSX, end=4
 Sorting: KCEALMPSX, end=3
 Sorting: ECAKLMPSX, end=2
 Sorting: CAEKLMPSX, end=1
  Sorted: ACEKLMPSX

Heapsort: Visualized

{ C, E, L, K, M, S, P, X, A }

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

for(i = (n-2)/2; i >= 0; i--) {
    siftDown(a, i, n);
}
i = 3, n = 9
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
  int left = 2*i+1;
  int right = 2*i+2;
  int largest = i;
i = 3, n = 9, left = 7, right = 8, largest = 3
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 3, n = 9, left = 7, right = 8, largest = 3
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, E, L, K, M, S, P, X, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    K  M S  P
   / \
  X   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
    int left = 2*i+1;
    int right = 2*i+2;
    int largest = i;
i = 7, n = 9, left = 15, right = 16, largest = 7
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 7, n = 9, left = 15, right = 16, largest = 7
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 7, n = 9, left = 15, right = 16, largest = 7
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 7, n = 9, left = 15, right = 16, largest = 7
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

for(i = (n-2)/2; i >= 0; i--) {
    siftDown(a, i, n);
}
i = 2, n = 9
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
    int left = 2*i+1;
    int right = 2*i+2;
    int largest = i;
i = 2, n = 9, left = 5, right = 6, largest = 2
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 2, n = 9, left = 5, right = 6, largest = 2
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 2, n = 9, left = 5, right = 6, largest = 5
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 2, n = 9, left = 5, right = 6, largest = 5
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 2, n = 9, left = 5, right = 6, largest = 5
{ C, E, L, X, M, S, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   L
     / \ / \
    X  M S  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 2, n = 9, left = 5, right = 6, largest = 5
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

for(i = (n-2)/2; i >= 0; i--) {
    siftDown(a, i, n);
}
i = 1, n = 9
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
    int left = 2*i+1;
    int right = 2*i+2;
    int largest = i;
i = 1, n = 9, left = 3, right = 4, largest = 1
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 1, n = 9, left = 3, right = 4, largest = 1
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ C, E, S, X, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      E   S
     / \ / \
    X  M L  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
  int left = 2*i+1;
  int right = 2*i+2;
  int largest = i;
i = 3, n = 9, left = 7, right = 8, largest = 3
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 3, n = 9, left = 7, right = 8, largest = 3
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, X, S, E, M, L, P, K, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    E  M L  P
   / \
  K   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 3, n = 9, left = 7, right = 8, largest = 7
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

for(i = (n-2)/2; i >= 0; i--) {
    siftDown(a, i, n);
}
i = 0, n = 9
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
    int left = 2*i+1;
    int right = 2*i+2;
    int largest = i;
i = 0, n = 9, left = 1, right = 2, largest = 0
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 0, n = 9, left = 1, right = 2, largest = 0
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 0, n = 9, left = 1, right = 2, largest = 1
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 0, n = 9, left = 1, right = 2, largest = 1
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 0, n = 9, left = 1, right = 2, largest = 1
{ C, X, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        C
       / \
      X   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 0, n = 9, left = 1, right = 2, largest = 1
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

void siftDown(char a[], int i, int n) {
    int left = 2*i+1;
    int right = 2*i+2;
    int largest = i;
i = 1, n = 9, left = 3, right = 4, largest = 1
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 1, n = 9, left = 3, right = 4, largest = 1
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(left < n && a[left] > a[largest]) { 
    largest = left;
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 1, n = 9, left = 3, right = 4, largest = 3
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(right < n && a[right] > a[largest]) { 
    largest = right;
}
i = 1, n = 9, left = 3, right = 4, largest = 4
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 1, n = 9, left = 3, right = 4, largest = 4
{ X, C, S, K, M, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      C   S
     / \ / \
    K  M L  P
   / \
  E   A

Heapsort: Visualized

if(largest != i) { 
    swap(a, i, largest);
    siftDown(a, largest, n);
}
i = 1, n = 9, left = 3, right = 4, largest = 4
{ X, M, S, K, C, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      M   S
     / \ / \
    K  C L  P
   / \
  E   A

Heapsort: Visualized

swap(a, 0, end);
end = 8
{ X, M, S, K, C, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        X
       / \
      M   S
     / \ / \
    K  C L  P
   / \
  E   A

Heapsort: Visualized

swap(a, 0, end);
end = 8
{ X, M, S, K, C, L, P, E, A }
  0  1  2  3  4  5  6  7  8

        A
       / \
      M   S
     / \ / \
    K  C L  P
   / \
  E   X

Heapsort: Visualized

Phew! That was a lot, from there on you just need to call siftDown on the root until everything is sorted.