C - 数组错误中的Heapsort实现

时间:2015-10-19 18:29:07

标签: c sorting heapsort

我试图在C中实现Heapsort算法,但我不确定我做得对。我也有一个错误"可变地修改了' A'在文件范围"。我在stackoverflow上搜索类似的主题,我发现heapSize应该是const,但是我不能将它用作函数中的变量。我该怎么办?

#include <stdio.h>
#include <math.h>

int heapSize = 100;
int length;
int A[heapSize];

int Heapify(int i) {
  int l = 2*i;
  int r = 2*i + 1;
  int largest;
  int tmp;

  if( l <= heapSize && A[l] > A[i]) largest = l;
  else largest = i;

  if (r <= heapSize && A[r] > A[largest]) largest = r;

  if (largest != i) {
    tmp = A[i];
    A[i] = A[largest];
    A[largest] = tmp;
    }
}

int BuildHeap() {
  heapSize = length;
  int i;

  for (i = floor(length/2); i <= 1; i--) {
    Heapify(i);
    }
}

int main(void) {
  int i,tmp;

  BuildHeap();

  for (i = length; i <= 2; i--) {
    tmp = A[heapSize];
    A[heapSize] = A[1];
    A[1] = A[heapSize];

    heapSize = heapSize - 1;

    Heapify(1);
    }
}

编辑: 我将程序的第一部分改为:

#include <stdio.h>
#define LENGTH 100


int heapSize = 10;
int A[LENGTH]

根据您的建议,更换&#34;楼层(长度/ 2)&#34;到&#34; LENGTH / 2&#34;。我通过编译解决了我的问题,但我很确定这个实现很糟糕。好吧,无论如何,非常感谢你的帮助。我真的很感激。

1 个答案:

答案 0 :(得分:1)

您的代码存在很多问题。

首先,您声明了一个全局int length变量,但您从未为其指定任何值。所以length总是零。

BuildHeap()你做:

    for (i = floor(length/2); i <= 1; i--) ...

floor(0/2)i==0开头。该值小于1因此循环使用i表达式进行第一次迭代并递减 i-- - i变为减去一个。然后循环继续,直到i值换过零变为正(并且大于1)。对于32位整数,它需要大约21.4亿次迭代......

main()做的第一件事就是调用BuildHeap(),而Heapify()又会调用(多次)A。后者比较数组项以决定它们是否应该交换 - 但它们没有分配任何值!您永远不会在A数组中填充任何数据......

您是否注意到您比较并交换了 <{1}}数组之外的项目(实际上,之前),因为BuildHeap()会减少i低于零,并将否定索引值传递给Heapify() ...?

您的Heapify例程在阵列中最多执行一次交换。它似乎不够。假设堆已经是3级深度,并且当前项看起来是堆中最小的一个;它应该达到最深层次,但你是如何实现这一目标的?单个交换将项目向下移动一级。

这就是你能做到的。

首先,确定要处理的数据的最大大小并准备数组:

#define LENGTH 100

int A[LENGTH + 1];

(你需要&#39;加上一个&#39;因为A[0]不会成为堆的一部分 - 为什么?)

然后准备变量来存储实际的数据大小:

int dataSize;
int heapSize;

和填充数组的例程。您可以从文件中读取用户输入或加载数据,或者只是通过某种算法填充数组。

void FillArrayAscending() {
    dataSize = 16;
    for(int i = 1; i <= dataSize; i ++)
        A[i] = i;
}
void FillArrayDescending() {
    dataSize = 25;
    for(int i = 1; i <= dataSize; i ++)
        A[i] = 50 - i;
}
void FillArrayCrossed() {
    dataSize = 20;
    for(int i = 1; i <= dataSize; i += 2)
        A[i] = 10 + i;
    for(int i = 2; i <= dataSize; i += 2)
        A[i] = 30 - i;
}

然后你就可以“堆积”了。要做到这一点,你需要在堆中筛选项目 - 你迭代交换,直到项目到达它的位置:

void SiftDown(int i) {
    while(i < heapSize) {
        int largest = i;

        if(2*i <= heapSize && A[i] < A[2*i])
            largest = 2*i;
        if(2*i + 1 <= heapSize && A[largest] < A[2*i + 1])
            largest = 2*i + 1;

        if(largest == i)
            break;  // the item reached its place

        A[0] = A[largest];
        A[largest] = A[i];
        A[i] = A[0];
        i = largest;  // new position to sift down...
    }
}

i表示要筛选的项目,largest表示交换目标,A[0]可以用作临时存储(为什么?)。

现在你可以在数组中构建一个堆:

void BuildHeap() {
    heapSize = dataSize;
    for(int i = heapSize/2; i >= 1; i --)
        SiftDown(i);
}

并按降序从堆中检索项目:

void ExtractHeap() {
    while(heapSize > 1) {
        A[0] = A[1];        // take the max item from a heap
        A[1] = A[heapSize]; // replace it with the last one
        A[heapSize] = A[0]; // add the max one to the sorted part
        heapSize --;
        SiftDown(1);        // re-heapify
    }
}

现在你可以进行整个处理:

int main(int, char**)
{
    FillArrayAscending();  // or Descending or...
    BuildHeap();
    ExtractHeap();

    // and here you can print the array contents
    // for indices 1 .. dataSize
    // to verify it is actually sorted
}