在C中实现堆排序时遇到麻烦

时间:2012-10-28 14:39:35

标签: c algorithm unix heap heapsort

我在C中实现了经典的堆排序算法。我几个小时都在盯着这段代码,但仍然无法弄清楚我的生活有什么不对。输入3 1 2 7 4 0 2运行良好并生成正确的堆,但是当我在末尾添加8时(并将大小增加1)。它不再产生堆。有任何想法吗?我认为这只是一个错误的愚蠢。供参考http://en.wikipedia.org/wiki/Heapsort

#include <ctype.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <string.h>

#define MAX_ARR 1024

void build_heap(int * fn, int len);
void heapify(int *f, int n, int size);
void verify_relations(int *f, int n);
void print_nums (int n[], int len);
void swap(int * a, int * b);
void heap_sort(int * a, int len);

int main(int argc, char **argv){
    /* input works -- 3 1 2 7 4 0 2 */
    /* input broken -- 3 1 2 7 4 0 2 8 */
    int nums[100] = { 3, 1, 2, 7, 4, 0, 2, 8 };

    int len = 8;

    build_heap(nums, len);
    verify_relations(nums, len);
    print_nums(nums, len);
    return 0;
}


void heap_sort(int nums[], int len){
    int i;
    build_heap(nums, len);
    for (i = len; i > 0; --i)
    {
        swap(&nums[1], &nums[i]);
        heapify(nums, 1, len);
    }

}

void build_heap(int * nums, int len) {
    int size = len, i;
    for (i = size; i >= 0; i--){
        heapify(nums, i, size);
    }
}

void heapify(int f[], int n, int size){

    int left = 2 * n,
    right = 2 * n + 1,
    largest = 0;

    if (left < size && f[left] >= f[n])
        largest = left;
    else
        largest = n;

    if (right < size && f[right] >= f[largest])
        largest = right;

    if (largest != n) {
        swap(&f[n], &f[largest]);
        heapify(&n, largest, size);
    }
}

void swap(int * a, int * b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

void verify_relations(int a[], int n){

    if (a[0] >= a[1] && a[0] >= a[2])
        printf("True - '%d >= %d && %d >= %d' \n", a[0], a[1], a[0], a[2]);
    else
        printf("False\n");

    if (a[1] >= a[3] && a[1] >= a[4])
        printf("True - '%d >= %d && %d >= %d' \n", a[1], a[3], a[1], a[4]);
    else
        printf("False\n");

    if (a[2] >= a[4] && a[2] >= a[5])
        printf("True - '%d >= %d && %d >= %d' \n", a[2], a[4], a[3], a[5]);
    else
        printf("False\n");
}


void print_nums (int n[], int len) {
    int c;
    for (c = 0; c < len; c++){
        printf("%d ", n[c]);
    }
}

2 个答案:

答案 0 :(得分:7)

该行

heapify(&n, largest, size);

应该是

heapify(f, largest, size);
        ^

答案 1 :(得分:1)

除了alestanis确定的主要错误之外,您应该考虑使verify_relations()代码更加彻底,因为它不会验证整个堆。

在数组索引从1开始的堆中(而不是在C中基于0),然后对于每个元素a[i],如果存在相应的元素a[i*2],则{{1 }};如果相应的元素a[i] <= a[i*2]存在,则a[i*2+1]

由于我们在C中使用基于0的索引,因此元素0中包含子项1,2;你有元素1有孩子3,4;你有2个孩子的元素2,5;因此,元素a[i] <= a[i*2+1]包含子i2*i+1

因此,您的2*i+2代码可能基于以下两个函数之一(verify_relations()verify_relations1())。区别在于verify_relations2()报告堆排序中的每个错误,但verify_relations1()仅报告第一个不匹配。在这两种情况下,当然,您会被告知堆无效,但有时更彻底的报告可能会使调试更容易。 我已将代码包含在测试工具中,主要是因为我希望在将代码发布到此处之前能够合理地确定代码是否正确。这意味着我有'标记'字符串来识别正在分析的内容以及发现的错误。您可能认为不需要所有标记。您可能还决定在verify_relations2()而不是stderr上或在传递给验证函数的文件流上生成函数报告(这样您就可以选择输出在运行时的位置)。

stdout