我试图在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;。我通过编译解决了我的问题,但我很确定这个实现很糟糕。好吧,无论如何,非常感谢你的帮助。我真的很感激。
答案 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
}