堆排序

来源:互联网 发布:linux 交叉编译ide 编辑:程序博客网 时间:2024/05/16 12:13

概述

堆,可以视为一颗完全二叉树,其节点之间满足父节点不小于(不大于)两个子节点的值,这样的堆被称为大(小)根堆。用数学符号表示为:

  1. 大根堆:A[parent(i)] >= A[i]
  2. 小根堆:A[parent(i)] <= A[i]

在堆排序中,需要能够快速的找到节点的父节点,及其左右孩子节点。例如数组A[0 … n],可以将下标与树的节点按照下图进行匹配。

heap_tree

通过上图的方式给树的节点与数组下标的建立对应关系,可以很容易的计算出节点的父节点、左孩子和右孩子节点的下标:

#define LEFT(i)     (((i) << 1) + 1)#define RIGHT(i)    (((i) << 1) + 2)#define PARENT(i)   (((i) - 1) >> 1)

若是数组下标从1开始对应树的根节点则有:

#define LEFT(i)     ((i) << 1)#define RIGHT(i)    (((i) << 1) + 1)#define PARENT(i)   ((i) >> 1)

堆排序的过程主要可以分为三个阶段:

  1. 建堆。建堆是利用堆化过程将一个大小为n的数组转换为最大(小)堆的过程。
  2. 堆化。堆化用于保持堆的特性,是堆排序中最为重要的过程。其思想是比较节点i和它左右孩子节点,并选择三者中最大(小)的元素。如果最大值不是节点i,则调换节点i与最大子节点的值,并递归的对子节点进行兑换过程。
  3. 排序。该操作是从堆中取出最大(小)元素,并通过堆化过程维持堆的特性。

堆排序的实现

#include <stdio.h>/**< 查找左孩子节点下标 */#define LEFT(i)     (((i) << 1) + 1)/**< 查找右孩子节点下标 */#define RIGHT(i)    (((i) << 1) + 2)/**< 查找父节点下标 */#define PARENT(i)   (((i) - 1) >> 1)/* @brief 堆化,保持堆的性质 * @param A [in] 数组地址 * @param len [in] 数组元素个数 * @param i [in] 需要堆化的元素的下标 */static voidheapify(int *A, int len, int i){  int largest;  int l, r;  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) {    int tmp = A[i];    A[i] = A[largest];    A[largest] = tmp;    heapify(A, len, largest);  /* 递归的对孩子节点进行堆化操作 */  }}/* @brief 建立堆 * @param A [in] 数组地址 * @param len [in] 数组元素个数 */static voidbuild_heap(int *A, int len){  int i = PARENT(len - 1);  while (i >= 0) {    heapify(A, len, i);    i--;  }}/* @brief 堆排序 * @param A [in] 待排序数组地址 * @param len [in] 待排序数组元素个数 */void hsort(int *A, int len){  int tmp;  build_heap(A, len);  len--;  while (len > 0) {    tmp = A[0];    A[0] = A[len];    A[len] = tmp;    heapify(A, len, 0);    len--;  }}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};  int len = sizeof(A) / sizeof(A[0]);  display(A, len);  hsort(A, len);  display(A, len);  return 0;}
0 0
原创粉丝点击