Optimizing Heap Sort
In the heap sort from the previous section, we allocated extra space to construct the heap and sort it. In this section, we optimize this by using in-place heap sort.
For a max heap, first swap the data at the starting position with the value at the end of the array, so the end of the array becomes the maximum element. Then perform a shift down operation on element W to regenerate the max heap. Next, swap the newly generated maximum value with the second-to-last position of the entire array, so that the second-to-last position holds the second-largest data. This process continues by analogy.
The entire process can be illustrated by the following diagram:

Java example code
Source code package download:Download
src/example/heap/HeapSort.java file code:
package example.heap;
import example.sort.SortTestHelper;
/**
* In-place heap sort
*/
public class HeapSort<T extends Comparable> {
public static void sort(Comparable[] arr) {
int n = arr.length;
// Note that our heap is indexed starting from 0 at this point
// Start from (index of last element - 1) / 2
// The index of the last element is n-1
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
shiftDown(arr, n, i);
for (int i = n - 1; i > 0; i--) {
swap(arr, 0, i);
shiftDown(arr, i, 0);
}
}
// Swap the two elements at indices i and j in the heap
private static void swap(Object[] arr, int i, int j) {
Object t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
// Original shiftDown process
private static void shiftDown(Comparable[] arr, int n, int k) {
while (2 * k + 1 < n) {
// Left child node
int j = 2 * k + 1;
// The right child node is larger than the left child node
if (j + 1 < n && arr[j + 1].compareTo(arr[j]) > 0)
j += 1;
// Larger than both child nodes
if (arr[k].compareTo(arr[j]) >= 0) break;
// Swap the values of the original node and the child node
swap(arr, k, j);
k = j;
}
}
// Test HeapSort
public static void main(String[] args) {
int N = 100;
Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
sort(arr);
// Gradually extract the data in heapify using extractMax
// The extraction order should be from largest to smallest
for (int i = 0; i < N; i++) {
System.out.print(arr[i] + " ");
}
// Ensure the arr array is sorted from largest to smallest
for (int i = 1; i < N; i++)
assert arr[i - 1] >= arr[i];
}
}
import example.sort.SortTestHelper;
/**
* In-place heap sort
*/
public class HeapSort<T extends Comparable> {
public static void sort(Comparable[] arr) {
int n = arr.length;
// Note that our heap is indexed starting from 0 at this point
// Start from (index of last element - 1) / 2
// The index of the last element is n-1
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
shiftDown(arr, n, i);
for (int i = n - 1; i > 0; i--) {
swap(arr, 0, i);
shiftDown(arr, i, 0);
}
}
// Swap the two elements at indices i and j in the heap
private static void swap(Object[] arr, int i, int j) {
Object t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
// Original shiftDown process
private static void shiftDown(Comparable[] arr, int n, int k) {
while (2 * k + 1 < n) {
// Left child node
int j = 2 * k + 1;
// The right child node is larger than the left child node
if (j + 1 < n && arr[j + 1].compareTo(arr[j]) > 0)
j += 1;
// Larger than both child nodes
if (arr[k].compareTo(arr[j]) >= 0) break;
// Swap the values of the original node and the child node
swap(arr, k, j);
k = j;
}
}
// Test HeapSort
public static void main(String[] args) {
int N = 100;
Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
sort(arr);
// Gradually extract the data in heapify using extractMax
// The extraction order should be from largest to smallest
for (int i = 0; i < N; i++) {
System.out.print(arr[i] + " ");
}
// Ensure the arr array is sorted from largest to smallest
for (int i = 1; i < N; i++)
assert arr[i - 1] >= arr[i];
}
}