function heapSort(array: number[]) {const length = array.length;
for (let i = (length >> 1) - 1; i >= 0; i--) siftDown(array, i, length);
for (let end = length - 1; end > 0; end--) {[array[0], array[end]] = [array[end], array[0]];
siftDown(array, 0, end);
}
}
function siftDown(array: number[], i: number, size: number) { while (true) {const left = 2 * i + 1, right = left + 1;
let largest = i;
if (left < size && array[left] > array[largest]) largest = left;
if (right < size && array[right] > array[largest]) largest = right;
if (largest === i) return;
[array[i], array[largest]] = [array[largest], array[i]];
i = largest;
}
}
Start: 24 values read as a binary tree: the children of i are 2i + 1 and 2i + 2.
Understanding Heap sort
The idea
Heap sort treats the array as a binary tree stored level by level: the children of index i sit at 2i + 1 and 2i + 2. It first rearranges the array into a max-heap, where every parent is at least as large as its children, so the maximum is at index 0.
Then it repeats n − 1 times: swap the root with the last element of the heap, shrink the heap by one, and sift the new root down until the heap property holds again. Each pop places one value in its final position, from the end backwards.
The four stages
Complexity
Versus its siblings
Pseudocode
HEAPSORT(array)
for i ← ⌊n/2⌋ − 1 down to 0: SIFTDOWN(array, i, n)
for end ← n − 1 down to 1
swap array[0], array[end]; SIFTDOWN(array, 0, end)
SIFTDOWN(array, i, size)
while a child of i is larger: swap with the larger child, descend
When to use
Pitfalls
History
J. W. J. Williams published heap sort in 1964, introducing the binary heap along with it. Robert Floyd improved it the same year with the O(n) bottom-up heap construction shown here, and the algorithm became the safety net of introsort, the sort behind most C++ standard libraries.