排序算法:堆排序

堆排序

数据结构之堆的基本操作这篇博客当中提到过一个堆排序。就是将一个堆的元素删除完毕过后,此时的数组内部就是一个有序的序列。

堆与排序

堆是一个完全二叉树,堆的任意一个节点都是以这个节点为根节点的树中的最值(最大或最小值)这样子的话,每一个堆的堆顶元素都是这个堆的最值。那么依次删除一个堆的堆顶,最后就能够得到一个有序的序列。

而堆排序就是利用了堆的这个性质来进行排序的过程。

思路

这里写图片描述

在进行彻底的删除完毕后,剩下的序列就是 2 3 4 5 6 9 这就就是一个有序的序列!!

所以堆排序的主要思路就是两个:
  1. 将数组构建成一个堆
  2. 依次删除这个堆

实现

void AdjustDown(int array[], int parent, int size) // 下沉式调整
{
  int child = 2 * parent + 1;
  while (child < size) {
    if ((child + 1) < size && array[child] < array[child + 1]) {
      child = child + 1;
    }
    if (array[parent] < array[child]) {
      Swap(&array[parent], &array[child]);
      parent = child;
      child = 2 * parent + 1;
    } else {
      break;
    }
  } // end while (1)
  return;
}

void HeapCreate(int array[], int size)
{
  if (size <= 1) {
    return;
  }

  int parent = (size - 1 - 1) / 2;

  for (; parent >= 0; parent--) {
    AdjustDown(array, parent, size);
  }
  return;
}

void HeapPop(int array[], int heap_bound)
{
  Swap(&array[0], &array[heap_bound - 1]);
  AdjustDown(array, 0, heap_bound - 1);
}

void HeapSort(int array[], int size)
{
  if (size <= 1) {
    return;
  }

  HeapCreate(array, size); // 创建堆

  int i = 0;
  for (; i < size; ++i) {
    // 由于每次删除堆的元素后
    // 堆的范围就变了
    // 所以这里定义一个 heap_bound 
    // 来确定堆的范围
    int heap_bound = size - i;
    HeapPop(array, heap_bound);
  }
  return;
}

堆的操作最核心的就是下沉与上浮,由于堆的删除是进行下沉操作的,所以这里在构建堆的时候也使用下沉的方式来构建堆。构建堆的时候先找到第一个父节点,可以根据最后一个叶子节点来计算出其父节点,接下来就是依次遍历,依次下沉的过程,最终构建一个堆。
删除的时候就是一个简单的堆顶删除,与最后一个叶子节点交换,接着下沉堆顶的叶子节点即可。

切记!!!

这里要注意的是,由于每次删除后,堆内元素减少,同时在下沉传参的时候一定要注意好传什么参数进去,以免对不属于堆的元素进行操作。

堆排序的时间复杂度是 O(N*logN),空间复杂度是 O(1)由于这里我们在原有的数组内部建立堆,并没有创建新的空间,所以是O(1),排序稳定性:不稳定。


欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值