堆排序(非递归)

概述

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

  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;
}
### Python 实现非递归堆排序 堆排序是一种基于比较的高效排序算法,其核心思想是利用二叉堆数据结构完成数组的最大值提取操作。为了实现非递归版的堆排序,可以按照以下逻辑构建代码。 #### 堆排序的核心思想 堆排序分为两个主要阶段:建堆和调整堆。 1. **建堆**:将输入列表构建成一个最大堆(或最小堆)。在此过程中,父节点始终大于等于子节点。 2. **调整堆**:通过不断移除根节点并重新调整剩余部分为新的堆,逐步得到有序序列。 以下是具体的非递归实现方式: ```python def heapify_non_recursive(arr, n, i): """ 非递归地调整堆 """ largest = i # 初始化当前节点为最大的索引 left_child = 2 * i + 1 # 左孩子节点索引 right_child = 2 * i + 2 # 右孩子节点索引 while True: if left_child < n and arr[left_child] > arr[largest]: largest = left_child if right_child < n and arr[right_child] > arr[largest]: largest = right_child if largest != i: # 如果最大值不是当前节点,则交换它们 arr[i], arr[largest] = arr[largest], arr[i] i = largest # 更新左孩子和右孩子的索引 left_child = 2 * i + 1 right_child = 2 * i + 2 else: break def heap_sort_non_recursive(arr): """ 使用非递归方法实现堆排序 """ n = len(arr) # 构建初始最大堆 for i in range(n // 2 - 1, -1, -1): heapify_non_recursive(arr, n, i) # 提取元素并重建堆 for i in range(n - 1, 0, -1): arr[0], arr[i] = arr[i], arr[0] # 将当前最大值移到最后 heapify_non_recursive(arr, i, 0) # 调整剩下的堆 # 测试代码 if __name__ == "__main__": data = [4, 10, 3, 5, 1] print("原始数组:", data) heap_sort_non_recursive(data) print("排序后的数组:", data) ``` #### 关键点解析 上述代码实现了堆排序的关键功能,并采用非递归的方式完成了 `heapify` 过程。具体说明如下: - 函数 `heapify_non_recursive` 是用来维护堆性质的核心函数,在循环中持续检查父子节点的关系并进行必要的交换[^3]。 - 初始堆化过程从最后一个非叶子节点开始向上逐层处理,确保整个树满足最大堆的要求。 - 排序阶段每次都将堆顶元素(最大值)移动到数组末尾,并缩小堆的有效范围,随后再次调用 `heapify_non_recursive` 来恢复堆属性。 此实现的空间复杂度保持在 \(O(1)\),因为所有的操作都在原数组上执行,无需额外分配内存空间。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值