了解堆

时间:2014-10-13 16:53:08

标签: c algorithm sorting heapsort

我看到的每一个参考资料都表明,构建堆的sift_down方法是理想的方法,但这是否意味着仍然可以使用sift_up构建堆?如果是这样,为什么sift_down更受欢迎?我正在尝试更好地理解我正在采用的算法课程。我想尝试实现一个使用sift_up的build_heap函数,但到目前为止我没有任何运气,尽管我已经设法使用sift_down让它工作。

任何人都可以分享的想法,建议或参考?这是我目前正在努力的一些功能:

#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;
}

1 个答案:

答案 0 :(得分:3)

你应该能够做到

for (int i = 1; i <= n; i++) sift_up(heap, i);

相当于逐个插入元素。最糟糕的运行时间是Theta(n log n),因为在最坏的情况下,每个新元素必须一直被筛选到根。该运行时间比sift_down heapify的运行时间差,即Theta(n)。区别在于sift_down可以将大多数元素向下移动几个级别,而sift_up可以将大部分元素移动到n级别。