第4节课仍然是讲排序,但介绍的是一种很高效的堆排序。

在编程过程中,有时候会需要进行extrat_max的操作,即从一个数列里挨个抽取最大值并将其它从原数列中移除。而排序问题也可以看作是一个extract_max的行为,不断的从原始数列中抽取最大值并进行移除,这样挨个抽取的最大值输出后能得到一个降序的数列。为了实现该排序思路,堆排序被提了出来,首先我们的了解下堆的概念:

堆(Heap):一个数列被可视化为一个近似完全二叉树,这个树则为堆。如下图所示:

在堆的基础上,有分:最大堆和最小堆。

  • 最大堆(Max-Heap):某节点的key 子节点的key。
  • 最小堆(Min-Heap):某节点的key  子节点的key。

为了构建最大堆,有个操作叫max_heapify,它就在子树根(subtree's root)上纠正违反最大堆属性(某节点的key ≥ 子节点的key),下图展示了一个max_heapify的例子。

从上图可以看出,倒数第二行(即n/2个元素)是向下比较一次,倒数第三行(n/4个元素)是向下比较两次,...。(问:为什么倒数第三行是向下比较两次?答:用上图的例子说明,如果倒数第三行的4需要修正最大堆属性,和14换,这是比较一次,而换后的4与8不合最大堆属性,所以又换了一次,这是第二次比较。加起来就两次比较)。那么n/2^k个元素的向下比较了k次,所以MAX_HEAPIFY(A, 跟节点)的复杂度Οlog2n(n/2^k≤1)。

对无序数列构建一个大堆堆的方法如下图所示,是以bottom-up的方式,从i=n/2结点位置依次向上遍历进行max_heapify操作

基于以上的方法,我们可以实现堆排序

  1. 将无序A数列构建一个堆。(Ο(n))
  2. 将堆进行max_heapify修正为最大堆。(Ο(log2n))
  3. 找到最大值元素A[1],即当前最大堆的跟节点。(Ο(1))
  4. 将A[1]和堆最后的元素A[n]进行交换。(Ο(1))
  5. 将元素A[n]撤出堆,减少堆大小。(Ο(1))
  6. 现在堆也许会违背最大堆属性,因此重复2-5步骤。(有n steps)

由于A(n)不断撤出,堆大小也会不断改变。复杂度不再是Ο(n + nlog2n) - 其中n为建堆,nlog2n中的第一个n是n steps,而第二个log2n是max_heapify,因为堆大小不断减小时,n和n都在同步减少,这样nlog2n实际上应为n,最后堆排序的时间复杂度为Ο(n)(Ο(n+n)=Ο(2n)=Ο(n))。

下图为一个堆排序的例子:

最新文章

  1. 如何托管ASP.NET Core应用到Windows Service中
  2. ios 证书申请和发布流程
  3. R扩展包
  4. MyRocks简介
  5. 第一周Web类WriteUp
  6. 关于<![CDATA[]]
  7. iOS-UI控件精讲之UIView
  8. 完全卸载oracle
  9. mysql innodb myisam 主要区别与更改方法
  10. BOOST 线程完全攻略 - 扩展 - 可被关闭的线程类
  11. js 获取 最近七天 30天 昨天的方法 -- 转
  12. AI繁荣下的隐忧——Google Tensorflow安全风险剖析
  13. [洛谷P1006] 传纸条
  14. git修改远程仓库关联
  15. 分治法——快速排序(quicksort)
  16. 如何给a标签绑定ajax事件
  17. Windows 下安装 tensorflow & keras & opencv 的避坑指南!
  18. [Python]关于return逻辑判断和短路逻辑
  19. CocurrentHashMap和HashTable区别分析
  20. 统计中的t检验

热门文章

  1. OpenSSL加密系统简介
  2. MeteoInfoLab脚本示例:地图投影
  3. 本地环境Django配置问题
  4. centos8平台使用wkhtmltopdf实现html网页转pdf
  5. selenium 图片懒加载
  6. JavaSE学习笔记01注释、标识符与基本类型
  7. Android 限制控件多次点击
  8. tomcat 启动失败
  9. APP打开(三)—激活率提升20%的思考
  10. 【Aspose.Words for Java】 对word文档,增加页眉,页脚,插入内容区图像,