概述
在上一篇文章中提到了堆排序的递归算法,递归算法相对于非递归算来来说主要有以下优点:
- 将原问题划分为一个规模更小的子问题(分治法)。
- 代码结构清晰,代码量少,可读性强。
但同时递归也存在以下缺点:
- 递归调用函数,时间开销大。
- 递归太深容易导致堆栈溢出。
为了能解决上述两个缺点,本文采用了非递归实现了非递归版本的堆排序算法。但需要注意的是,非递归版的堆排序算法,减少了函数的调用次数,避免了堆栈溢出的可能,但是其代码相对较为复杂,且不容易理解。
堆排序实现(非递归版)
#include <stdio.h>
#define LEFT(i) (((i) << 1) + 1)
#define RIGHT(i) (((i) << 1) + 2)
#define PARENT(i) (((i) - 1) >> 1)
void heap_sort(int *A, int len)
{
int l, r, largest;
int i, j, tmp;
i = PARENT(len - 1); /* Get the last non-leaf node */
while (i >= 0) { /* Build the heap */
l = LEFT(i);
r = RIGHT(i);
largest = i;
if (l < len && A[l] > A[largest]) {
largest = l;
}
if (r < len && A[r] > A[largest]) {
largest = r;
}
if (largest != i) {
tmp = A[i];
A[i] = A[largest];
A[largest] = tmp;
i = largest;
} else {
i--;
}
}
len--;
while (len > 0) {
tmp = A[0]; /* Sort */
A[0] = A[len];
A[len] = tmp;
len--;
i = 0;
while (1) { /* Heapify */
l = LEFT(i);
r = RIGHT(i);
if (l < len && A[l] > A[largest]) {
largest = l;
}
if (r < len && A[r] > A[largest]) {
largest = r;
}
if (largest != i) {
tmp = A[i];
A[i] = A[largest];
A[largest] = tmp;
i = largest;
} else {
break;
}
}
}
}
void display(int *A, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%d ", A[i]);
}
printf("\n");
}
int main()
{
int A[] = {10, 32, 43, 31, 2, 45, 12, 9, 71, 41, 10, -19, 32, 4, 8, 6};
int len = sizeof(A) / sizeof(A[0]);
display(A, len);
heap_sort(A, len);
display(A, len);
return 0;
}
堆排序实现(非递归通用版)
为了满足通用性,本文同样实现了类似于库函数qsort排序算法的通用版。
#include <stdio.h>
#define LEFT(i) (((i) << 1) + 1)
#define RIGHT(i) (((i) << 1) + 2)
#define PARENT(i) (((i) - 1) >> 1)
#define SWAP(a, b, size) \
do { \
size_t __size = (size); \
unsigned char *__a = (a), *__b = (b); \
do { \
unsigned char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while(0)
void display(int *A, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%d ", A[i]);
}
printf("\n");
}
/* @brief The hsort() function sorts an array with nmemb
* elements of size size.
* @param base [in] The start of the array.
* @param nmemb [in] The number of elements in array.
* @param size [in] The size of the element.
* @param compare [in] The comparison function.
*/
void hsort(void *base, size_t nmemb, size_t size,
int (*compare)(const void *, const void *))
{
int l, r, i, largest;
i = PARENT(nmemb - 1); /* Get the last non-leaf node */
/* First build heap */
while (i >= 0) {
l = LEFT(i);
r = RIGHT(i);
largest = i;
if (l < nmemb && compare(base + l * size, base + largest * size) > 0) {
largest = l;
}
if (r < nmemb && compare(base + r * size, base + largest * size) > 0) {
largest = r;
}
if (largest == i) {
i--;
} else {
SWAP(base + i * size, base + largest * size, size);
i = largest;
}
}
while (--nmemb > 0) {
SWAP(base, base + nmemb * size, size); /* Sort: get the max element */
i = 0; /* Heapify */
while (1) {
l = LEFT(i);
r = RIGHT(i);
largest = i;
if (l < nmemb && compare(base + l * size, base + largest * size) > 0) {
largest = l;
}
if (r < nmemb && compare(base + r * size, base + largest * size) > 0) {
largest = r;
}
if (largest == i) {
break;
}
SWAP(base + i * size, base + largest * size, size);
i = largest;
}
}
}
int compare(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
int main()
{
int A[] = {10, 32, 43, 31, 2, 45, 12, 9, 71, 41, 10, -19, 32, 4, 8, 6};
int len = sizeof(A) / sizeof(A[0]);
display(A, len);
hsort(A, len, sizeof(int), compare);
display(A, len);
return 0;
}