1. 简述

假设待排序数组为 int array[], 数组长度为n。
    主要是利用堆的性质。对于升序排序,使用最大堆。
    首先,建堆,使用递归后根序遍历得方法,通过交换元素,保证根元素比孩子元素大。
    第1趟,堆顶元素array[0]与array[n-1]交换,保证array[n-1]的数值正确,根据array[0]新的数值更新堆。
    第2趟,堆顶元素array[0]与array[n-2]交换,保证array[n-2]的数值正确,根据array[0]新的数值更新堆。
    ···

第n-1趟,堆顶元素array[0]与array[1]交换,保证array[1]的数值正确,根据array[0]新的数值更新堆。

2. 复杂度

平均时间复杂度为O(N*logN),空间复杂度为O(1)。

3. 代码

void make_heap(int array[], int n, int node) { // 自底向上,构建堆
  int left = 2 * node + 1;
  int right = 2 * node + 2;
  if(left > n-1) return;
  else if(right > n-1) { // 堆是完全的二叉树,所以此时不需要递归
    if(array[node] < array[left]) {
      swap(array[node], array[left]);
    }
  }
  else {
    make_heap(array, n, left);
    make_heap(array, n, right);
    if(array[node] < array[left] && array[right] <= array[left]) {
      swap(array[node], array[left]);
    }
    else if(array[node] < array[right] && array[left] <= array[right]) {
      swap(array[node], array[right]);
    }
  }
}
void update_heap(int array[], int n, int node) { // 自顶向下,更新堆
  int left = 2 * n + 1;
  int right = 2 * n + 2;
  if(left > n-1) return;
  else if(right > n-1) {
    if(array[node] < array[left]) 
      swap(array[node], array[left]);
  }
  else {
    if(array[node] < array[left] && array[right] <= array[left]) {
      swap(array[node], array[left]);
      update_heap(array, n, left);
    }
    else if(array[node] < array[right] && array[left] <= array[right]) {
      swap(array[node], array[right]);
      update_heap(array, n, right);
    }
  }
}
void heap_sort(int array[], int n) {
  make_heap(array, n, 0);
  for(int i=n; i>=1; i--) {
    swap(array[i], array[0]);
    update_heap(array, n, node);
  } 
}

实际上,堆的构建和更新都可以使用非递归的方式实现,对于堆的构建,需要首先找到最后一个有孩子的节点array[k],然后从array[k]一直更新到array[0]即可,其中的k=n/2。k的求法如下:假设k存在,2*k+1=n或者2*k+2=n,对于第一种情况,k==n/2,对于第二种情况,k==n/2-1。对于堆的更新,就更简单了,只要从array[0]开始,选择一条通路,一直向下更新,直到没有孩子了为止。
   值得注意的是,对于下标从0开始的数组,k号节点的孩子节点分别是2*k+1和2*k+2。 而对于下标从1开始得数组,k号节点的孩子节点分别是2*k和2*k+1。
    堆排序属于选择排序,实际上就是利用最大堆这个数据结构,每次选择一个剩余元素中最大的元素,交换到合适的位置上去。

4. 参考资料

维基百科-堆排序    http://en.wikipedia.org/wiki/Heapsort

算法熟记-排序系列-堆排序相关推荐

  1. 高效排序算法——希尔排序、堆排序、归并排序、快速排序

    如标题,这里讨论的是基于比较的排序算法中最高效的三种算法和希尔排序.堆排序.归并排序.快速排序的平均时间复杂度均为O(NlogN).前面有介绍过O(N2)的三种简单排序算法(见三大简单排序算法--插入 ...

  2. shell sort 最后一列排序_十个必知的排序算法|Python实例系列[1]

    实例内容: 十个必知的排序算法具体代码,并简略的得知每种算法对于不同长度数列的排序时间 十大排序: 1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序7.堆排序8.计数排序9.桶 ...

  3. 冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序等常用排序算法的比较

    掌握好常用的排序算法,在实际的项目开发中可以节省很多的时间.每一种排序算法在执行的效率上是存在差别的,这些微小的时间差,也许在平常的联系当中感觉不到,但是涉及到数据量比较大或者是在资源比较紧张的系统中 ...

  4. 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序...

    先推荐一篇关于排序算法的文章:http://www.cppblog.com/guogangj/archive/2009/11/13/100876.html 本文思路部分来源于上篇文章,但测得的结果似乎 ...

  5. C语言排序算法 选择排序 插入排序 快速排序 qsort实现快排 堆排序

    常见排序算法 选择排序 选择排序(Selection sort)是一种简单直观的排序算法. 它的工作原理如下. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素 ...

  6. 排序算法之选择排序(简单选择排序、堆排序)

    选择排序(简单选择排序.堆排序) 选择排序 简单选择排序 概念 算法实现 堆排序 概念 算法实现 后续 选择排序 选择排序的基本思想是:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列 ...

  7. 数据结构—排序算法总结(插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、合并排序、计数排序)

    *排序 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性 在待排序的数组中,如果出现多个相同的关键字,例如:98751555512,中出现重复的数字,在 ...

  8. 堆排序时间复杂度_leetcode刷题(二):排序算法(归并排序,堆排序,桶排序)...

    今天,我们要来讲讲排序问题,这次讲的排序算法主要是归并排序,堆排序和桶排序. 归并排序 归并一词在中文的含义就是"合并,并入"的意思,在数据结构里面就是将两个或者两个以上的有序数组 ...

  9. java 快速排序算法简单_排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序......

    先推荐一篇关于排序算法的文章:http://www.cppblog.com/guogangj/archive/2009/11/13/100876.html 本文思路部分来源于上篇文章,但测得的结果似乎 ...

最新文章

  1. canvas 图片不能缩放显示在画布的问题 忘记设置dw,dh
  2. 解决 Git: There is no tracking information for the current branch.的问题
  3. 苹果手机更改照片大小kb_苹果手机照片视频删除了怎样恢复?专业人士建议你这样做...
  4. Java基础--成员变量和局部变量(区别、重名问题)
  5. java 判断正负数_Java判断一个字符串为数字(正负、小数)
  6. 第一次使用pyqt5解决的几个小问题
  7. day 05 字典dic(增删改查 嵌套)
  8. 基于STEP7 V5.xWinCC V7.x快速开发项目
  9. 设计模式在实际业务应用中的介绍之3——外观或门面模式Facade对AOP装配业务工厂的应用...
  10. JAVA 蔡羽 基础知识漫谈
  11. send/recv与socket
  12. 学习打印机,了解打印命令
  13. Linux下Makefile的automake生成全攻略[zz]
  14. 【系统】Win10 新装系统提示 OOBEIDPS
  15. python fft ifft
  16. 项目管理软件,协同管理软件介绍
  17. 使用Hydra通过ssh破解密码
  18. 10种流行的机器学习算法进行泰坦尼克幸存者分析
  19. ros ubuntu 卸载_ROS的安装和卸载
  20. 谷歌硬盘,百度云盘等超大文件利用IDM加速下载,防止限流方法

热门文章

  1. android 线性布局蒙层,Android开发 - 掌握ConstraintLayout(一)传统布局的问题
  2. C语言多个变量运算存储过程,postgresql函数中的赋值运算和postgresql函数存储过程实现数据批量插入...
  3. 代码重构 防火墙 相关知识
  4. Android Glide图片加载框架(四)回调与监听
  5. 三种钱非常奥妙 花越多就赚越多
  6. 国家部委对4G调研:未定给中电信联通发放牌照
  7. Shell 字符串截取
  8. 写给大数据开发初学者的话4
  9. 《学习R》笔记:科学计算器、检查变量和工作区、向量、矩阵和数组、列表和数据框...
  10. shell字符串的用法