next up previous index
Next: Code and demonstration Up: Heap Sort Previous: Efficiency   Index


Sorting by removal

Now we have converted the original array to a heap, it is simple to order it by repeatedly applying the heap removal algorithm.

When implementing priority queues, using binary heaps, the remove method returned the maximum element. Instead of returning it, we now just move it to the appropriate place at the end of the array. The reason we can do this, is that the heap is smaller by one when we remove an element, so another place is always freed up at the end each time.

Consider where we have got to as a result of heapifying the array. This was $[42, 35, 40, 10, 31]$ which we can picture as


\begin{picture}(800,120)(0,-20)
\put(50,50){\makebox(0,0){42}}
\put(0,0){\line...
...){\makebox(0,0){\small 6}}
\put(750,-35){\makebox(0,0){\small 7}}
\end{picture}
Now when we remove the maximum element, which is always the first, the remove algorithm tells us to put the last element in the first position, and then demote it until we reestablish heap order. We can do both relocations at once by swapping the first and last element. This gives

\begin{picture}(800,120)(0,-20)
\put(50,50){\makebox(0,0){31}}
\put(0,0){\line...
...){\makebox(0,0){\small 6}}
\put(750,-35){\makebox(0,0){\small 7}}
\end{picture}
where the thick line indicates that we are now only concerned with the first four elements. The segment of the array after the thick line is the sorted array that we are building up.

Now the first four elements are not in heap order. So we need to apply the demote method, with size reduced by 1, beginning with the root node as parent. This is easily seen to produce the array


\begin{picture}(800,120)(0,-20)
\put(50,50){\makebox(0,0){40}}
\put(0,0){\line...
...){\makebox(0,0){\small 6}}
\put(750,-35){\makebox(0,0){\small 7}}
\end{picture}
Repeating the same procedure, of swapping the first and last elements of the heap (ignoring the 42 which is no longer part of the heap), we obtain

\begin{picture}(800,120)(0,-20)
\put(50,50){\makebox(0,0){10}}
\put(0,0){\line...
...){\makebox(0,0){\small 6}}
\put(750,-35){\makebox(0,0){\small 7}}
\end{picture}
which again needs to be restored to heap order. Repeating this routine until the heap is empty, will provide us with a sorted array. The code for this part of the routine is simple:
for (int i = n - 1; i > 0; i--) {
    swap(a, i, 0);
    demote(a, i, 0);
}
This assumes that the array is originally in heap order. The index i begins with the last element of the array which is at n-1. This is swapped with the first element, which is at 0, and then demote is called with i as the current size of the array, and with the root 0 as parent. The swap routine simply exchanges the contents of a[i] and a[0].

The final code for the heapSort routine is shown in Figure 10.1.

Figure 10.1: A class providing the heap sort method.
public class Sort {

    private Sort() {}

    public static final void heapSort(Comparable[] a, int n) {
        if (n < 2) {
            return;
        }
        for (int i = (n / 2) - 1; i >= 0; i--) {
            demote(a, n, i);
        }
        for (int i = n - 1; i > 0; i--) {
            swap(a, i, 0);
            demote(a, i, 0);
        }
    }

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

    private static void demote(Comparable[] heap, int size, int parent) {
        Comparable item = heap[parent];
        int child; 
        while ((child = (2 * parent) + 1) < size) {
            if (child + 1 < size && heap[child].compareTo(heap[child + 1]) < 0) {
                ++child;
            }
            if (item.compareTo(heap[child]) < 0) {
                heap[parent] = heap[child];
                parent = child;
            } else break;
        }
        heap[parent] = item;
    }

}

The code has been placed in a Sort class which might include other sorting routines such as quickSort, mergeSort, shellSort etc. One advantage of heapSort is that it is a genuinely in-place routine requiring no auxiliary storage. Another is that it is an ${\cal
O}(n\log n)$ process, not only on average, but also in its worst case performance.


next up previous index
Next: Code and demonstration Up: Heap Sort Previous: Efficiency   Index
Peter Williams 2005-06-07