堆排序(非递归)

概述

上一篇文章中提到了堆排序的递归算法,递归算法相对于非递归算来来说主要有以下优点:

  1. 将原问题划分为一个规模更小的子问题(分治法)。
  2. 代码结构清晰,代码量少,可读性强。

但同时递归也存在以下缺点:

  1. 递归调用函数,时间开销大。
  2. 递归太深容易导致堆栈溢出。

为了能解决上述两个缺点,本文采用了非递归实现了非递归版本的堆排序算法。但需要注意的是,非递归版的堆排序算法,减少了函数的调用次数,避免了堆栈溢出的可能,但是其代码相对较为复杂,且不容易理解。

堆排序实现(非递归版)

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值