我正在用C语言编写排序应用程序,因为我有一个算法(堆排序)。这是我的代码:
void heap_sort(int *array, int size) {
int temp;
heap_build(array, size);
for(int i = size; i>1; i--) {
temp = array[i];
array[i] = array[1];
array[1] = temp;
size--;
heap_heapify(array, size, 1);
}
}
void heap_build(int *array, int size) {
for(int i = size / 2; i > 0; i--)
heap_heapify(array, size, i);
}
void heap_heapify(int *array, int size, int i) {
int largest, temp,
l = 2 * i, r = (2 * i) + 1;
if(l <= size && array[l] > array[i])
largest = l;
else
largest = i;
if(r <= size && array[r] > array[largest])
largest = r;
if(largest != i) {
temp = array[largest];
array[largest] = array[i];
array[i] = temp;
heap_heapify(array, size, largest);
}
}
结果是例如:
-22
-33686019 // the range is <-100, 100>
-71
-68
-59
-17
-8
43
59
82
你怎么看,数字没有正确排序,我有一个有线号码(总是在数组[1]中)。
答案 0 :(得分:1)
在评论中,您提到您在1..N
区间使用数组索引来获取大小为N+1
的数组,但传入的大小为N+1
。如果这是真的,那么max-heapify()
中就会出现一个错误:如果size
为N+1
,则您可以访问的最后一个位置是N
,而不是{{1}因此,您必须将比较更改为N+1
(对于l < size
也是如此):
r
或者,如果您希望代码尽可能接近CLRS,只要您将void heap_heapify(int *array, int size, int i) {
int largest, temp,
l = 2 * i, r = (2 * i) + 1;
if(l < size && array[l] > array[i])
largest = l;
else
largest = i;
if(r < size && array[r] > array[largest])
largest = r;
if(largest != i) {
temp = array[largest];
array[largest] = array[i];
array[i] = temp;
heap_heapify(array, size, largest);
}
}
作为大小而不是<=
传递,就可以使用N
(所以,你分配了一个N+1
元素数组,但是你传递了N+1
作为大小,所以事情排成一行。)
[旁注:我一直在告诉我,CLRS使用从1开始索引的数组。这在编写基于伪代码的实际代码时总会造成麻烦。)
在N
中也是如此,要么将heap_sort()
作为N
元素数组的大小传递,要么将N+1
初始化为i
:< / p>
size-1
这是一个包含工作代码的完整程序:
void heap_sort(int *array, int size) {
int temp;
heap_build(array, size);
for(int i = size-1; i>1; i--) {
temp = array[i];
array[i] = array[1];
array[1] = temp;
size--;
heap_heapify(array, size, 1);
}
}
打印:
#include <stdio.h>
void heap_build(int *array, int size);
void heap_heapify(int *array, int size, int i);
void heap_sort(int *array, int size) {
int temp;
heap_build(array, size);
for(int i = size-1; i>1; i--) {
temp = array[i];
array[i] = array[1];
array[1] = temp;
size--;
heap_heapify(array, size, 1);
}
}
void heap_build(int *array, int size) {
for(int i = size / 2; i > 0; i--)
heap_heapify(array, size, i);
}
void heap_heapify(int *array, int size, int i) {
int largest, temp,
l = 2 * i, r = (2 * i) + 1;
if(l < size && array[l] > array[i])
largest = l;
else
largest = i;
if(r < size && array[r] > array[largest])
largest = r;
if(largest != i) {
temp = array[largest];
array[largest] = array[i];
array[i] = temp;
heap_heapify(array, size, largest);
}
}
int main(void) {
int arr[] = { 0, -22, 2, -33, 82, 71, 82, 0, -68, -59, -17, -8, 43, 59, -100 };
heap_sort(arr, sizeof(arr)/sizeof(arr[0]));
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
printf("%d\n", arr[i]);
}
return 0;
}
请注意,第一个元素永远不会被排序;因为你使用了索引0
-100
-68
-59
-33
-22
-17
-8
0
2
43
59
71
82
82
,所以你基本上忽略了元素0.一个快速的黑客是在数组开始之前传入指向一个元素的指针,但这很难看,而且UB(指针算法只有效)如果结果指针引用了数组中的元素,或者引用了结尾的一个元素。)
所以我建议重构代码并忘记基于1的索引。这可以通过调整公式来计算节点的左子节点和调整循环条件来完成:
1..N
与先前版本的不同之处在于:
#include <stdio.h>
void heap_build(int *array, int size);
void heap_heapify(int *array, int size, int i);
void heap_sort(int *array, int size) {
int temp;
heap_build(array, size);
for(int i = size-1; i > 0; i--) {
temp = array[i];
array[i] = array[0];
array[0] = temp;
size--;
heap_heapify(array, size, 0);
}
}
void heap_build(int *array, int size) {
for(int i = size/2; i >= 0; i--)
heap_heapify(array, size, i);
}
void heap_heapify(int *array, int size, int i) {
int largest, temp,
l = i*2+1, r = l+1;
if (l < size && array[l] > array[i])
largest = l;
else
largest = i;
if (r < size && array[r] > array[largest])
largest = r;
if (largest != i) {
temp = array[largest];
array[largest] = array[i];
array[i] = temp;
heap_heapify(array, size, largest);
}
}
int main(void) {
int arr[] = { 0, -22, 2, -33, 82, 71, 82, 0, -68, -59, -17, -8, 43, 59, -100 };
heap_sort(arr, sizeof(arr)/sizeof(arr[0]));
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
printf("%d\n", arr[i]);
}
return 0;
}
中,循环条件变为heap_sort
。i > 0
中,循环条件变为heap_build()
。i >= 0
中,左边的孩子是heap_heapify()
而不是2*i+1
,2*i
是r
。