A heap is not a sorted array. It makes one smaller promise: every parent is no larger than either of its children. The array representation gives each node a fixed place in a complete binary tree, so that promise is enough to make the smallest value immediately available at the root.
Start where a violation can exist
Leaves already satisfy the promise: they have no children to contradict them.
The last parent is therefore the only sensible place to begin. In an array of
length n, it lives at floor(n / 2) - 1.
Start at the last parent. Index 2 already precedes both children.
Repair one subtree at a time
When a parent is too large, exchange it with its smaller child, then continue at the child’s old position. By visiting parents from right to left, every subtree below the current node has already been repaired.
for (let parent = Math.floor(heap.length / 2) - 1; parent >= 0; parent -= 1) {
siftDown(heap, parent);
}
This is bottom-up heap construction. Although it calls siftDown many times,
most nodes sit near the leaves and can move only a short distance. The total
work is O(n), not O(n log n).