Every reference I look at to learn about heaps says that the sift_down approach to building heaps is the ideal way, but does this mean that it is still possible to build a heap using sift_up? If so, why is sift_down preferred? I'm trying to get a better understanding of these types of things for an algorithms course I am taking. I'd like to try to implement a build_heap function that uses sift_up, but so far I haven't had any luck, though I have managed to get it to work using sift_down.
Any ideas, suggestions, or references that anyone could share? Here's a few functions I'm struggling with at the moment:
#include <stdio.h>
void bottom_up_heapsort(int*, int);
void heapsort(int*, int);
void sift_up(int*, int);
void sift_down(int*, int);
void build_max_heap(int*, int);
void bottom_up_build_max_heap(int*, int);
void swap(int*, int*);
int heapsize;
int main() {
int A[] = { 7, 12, 1, -2, 0, 15, 4, 11, 9 };
int B[] = { 7, 12, 1, -2, 0, 15, 4, 11, 9 };
int i;
int size = 9;
printf("Unsorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", A[i]);
}
heapsort(A, size);
printf("\n");
printf("Sorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", A[i]);
}
printf("\n");
printf("----------------------------------\n");
printf("Unsorted array for bottom up: \n");
for(i = 0; i < size; i++) {
printf(" %d ", B[i]);
}
bottom_up_heapsort(B, size);
printf("\n");
printf("Sorted array: \n");
for(i = 0; i < size; i++) {
printf(" %d ", B[i]);
}
printf("\n");
return 0;
}
void bottom_up_heapsort(int* arr, int len) {
int i;
bottom_up_build_max_heap(arr, len);
for(i = len-1; i >= 1; i--) {
sift_up(arr, len);
heapsize--;
swap(&arr[i], &arr[0]);
}
}
void heapsort(int* arr, int len) {
int i;
build_max_heap(arr, len);
for(i = len-1; i >= 1; i--) {
swap(&arr[0], &arr[i]); // move arr[0] to its sorted place
heapsize = heapsize - 1;
sift_down(arr, 0); // repair the heap
}
}
void sift_down(int* arr, int i) {
int l = 2*i, r = 2*i+1;
int largest;
if(l < heapsize && arr[l] > arr[i]) {
largest = l;
}
else {
largest = i;
}
if(r < heapsize && arr[r] > arr[largest]) {
largest = r;
}
if(largest != i) {
swap(&arr[i], &arr[largest]);
sift_down(arr, largest);
}
}
void sift_up(int* arr, int i) {
if(i == 1) return; // at the root
if(arr[i] > arr[i/2]) {
swap(&arr[i], &arr[i/2]);
sift_up(arr, i/2);
}
}
void bottom_up_build_max_heap(int* arr, int len) {
heapsize = len;
int i;
for(i = 0; i <= len; i++) {
sift_up(arr, i);
}
}
void build_max_heap(int* arr, int len) {
heapsize = len;
int i;
for(i = len/2; i >= 0; i--) {
// invariant: arr[k], i < k <= n are roots of proper heaps
sift_down(arr, i);
}
}
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
You should be able to do
for (int i = 1; i <= n; i++) sift_up(heap, i);
which is equivalent to inserting the elements one by one. The worst-case running time is Theta(n log n), since in the worst case each new element must be sifted all the way to the root. This running time is worse than that of the sift_down heapify, namely, Theta(n). The difference is that sift_down can move the majority of elements only a couple levels down, while sift_up can move the majority of elements log n levels up.