The BuildHeap
method that sifts elements down is the fastest known way to take an existing array and turn it into a heap. It's faster than inserting one item at a time, and it's faster than sifting elements up from the bottom.
However, once a heap is built, and you're doing a series of inserts and removes on the data structure, it's faster to insert items at the bottom and sift them up than it is to insert at the top and sift down.
Remember that in a heap of n items, n/2 items are at the leaf level. This means that when you insert an item (by adding it as the next leaf), there's a 50% chance that it won't have to sift up: it's already in the proper place. There's a 25% chance that it belongs on the next level up. As you move up in the heap, the probability of the item sifting up to that level decreases by 50%.
Now, you could write you heap code to do the insert at the top all the time, but the probabilities work against you. There's still a 50% chance that the item you inserted will end up at the leaf level. Except if you insert at the top it's going to take you log(n) swaps to get it there.
So if you insert at the bottom and sift up:
50% of the time you make 0 swaps
25% of the time you make 1 swap
12.5% of the time you make 2 swaps
...
If you insert at the top and sift down:
50% of the time you make log(n) swaps
25% of the time you make log(n)-1 swaps
12.5% of the time you make log(n)-2 swaps
...
Come to think of it, it's worse than that. Because if you're inserting an item and it ends up landing somewhere in the middle, you then have to take the item it displaced and sift it down. And that's going to end up moving things down all through the heap. In the end, inserting at the top always costs you log(n) swaps, because you eventually have to place something at the (n+1)th position in the array (i.e. you have to add an item).
It should be clear that you don't want to be inserting at the top, although you have to do something quite similar when you remove the root.
When you remove the root, you take the last item in the heap, put it in the root position, and sift it down. Considering that you got it from the leaf level, and considering that the leaf level contains half of the items, there's a pretty good chance (a little better than 50%) that it's going to end up back at the leaf level. Note that this won't always cause log(n) swaps, because you're not inserting an item; you're just re-adjusting the heap.
This is why, by the way, in a well-written binary heap implementation, removing the root element is more expensive than inserting a new item.