前言

什么是堆

堆是一种数据结构,它是完全二叉树或者是近似完全二叉树的一种数据结构,树中每个结点的值都不小于(或不大于)其左右孩子结点的值。

何为完全二叉树

完全二叉树是一种特殊的二叉树,完全二叉树是除了最后一层之外的其他每一场层都被完全填充,叶子节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树,也就是说所有节点都保持向左对齐。如果想了解更多关于二叉树的介绍,可参考之前写的一篇文章《【数据结构实践】手把手带你快速实现自定义二叉树

对完全二叉树来说,较为简洁的实现方法就是使用数组来存储完全二叉树。这样结点就按层序存储于数组中,其中第一个结点将存储于数组中的 1 号位,并且数组 i 号位表示的结点的左孩子就是 2i 号位,而右孩子则是(2i+1)号位。

什么是堆排序

堆排序与快速排序,归并排序一样都是时间复杂度为 O(N*logN)的几种常见排序方法,堆排序是将数据看成完全二叉树,然后根据完全二叉树的特性来进行排序的一种排序算法,这有点草船借箭的妙用。正所谓他山之,石可以攻玉。在堆排序中,堆具体可分为最大堆和最小堆,也有人称他们为大顶堆和小顶堆,如果父节点的值大于或等于孩子结点的值,那么称这样的堆为最大堆,这时每个节点的值都是以其为根结点的子树的最大值,即最大堆要求节点的元素都大于其对应的叶子节点,通常被用来进行升序排序,如果父节点的值小于或等于孩子结点的值,那么称这样的堆为最小堆,这时每个节点的值都是以其为根结点的子树的最小值,即最小堆要求节点的元素都小于其对应的叶子节点,通常被用于降序排序。堆一般用于优先队列的实现,而优先队列默认情况下使用的是最大堆。

小结:

最大堆:每个节点的值都大于或者等于它的左右子节点的值。

最小堆:每个节点的值都小于或者等于它的左右子节点的值。

如下图:

以最大堆为例,利用最大堆的结构特点,每个最大堆的根节点必然会是数组中最大的元素,构建一次最大堆,就可以获取数组中最大的元素。剔除最大元素后,反复构建剩下的数字为最大堆,获取根元素,最终保证数组有序。最大堆和最小堆是对称关系,学会其中一种即可

综上所述我们可以得出以下性质:

对于最大堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]

对于最小堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]

堆排序的算法设计

具体步骤如下:

  1. 将待排序的数组构造成一个最大堆,根据最大堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素
  2. 数组转换成最大堆之后,将堆顶元素取出,然后将剩下的节点重新构建为最大堆
  3. 重复步骤 2,如此反复,直到剩余数只有一个时结束,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值
  4. 交换数据,最后,就得到一个有序的数组了

代码实现

1.定义最大堆函数,传入当前节点的位置,左孩子位置是 2*root+1.调整位置使堆顶元素最大

def siftdown(arr, node, end): #arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]root = node   # 当前节点的位置while True:# 从root开始对最大堆调整child = 2 * root +1  #左(left)孩子的位置if child  > end:break# 找出两个child中较大的一个if child + 1 <= end and arr[child] < arr[child + 1]: #如果左边小于右边child += 1 #左右两孩子中选择较大者if arr[root] < arr[child]:# 最大堆小于较大的child, 交换顺序tmp = arr[root]arr[root] = arr[child]arr[child]= tmproot = child #else:# 无需调整的时候, 跳出循环break

2.定义堆排序函数,传递待排数组,逐次遍历,

def heap_sort(arr):# 从最后一个有子节点的孩子开始调整最大堆,不断的缩小调整的范围直到第一个元素first = len(arr) // 2 -1for i in range(first, -1, -1):siftdown(arr, i, len(arr) - 1)# 将最大的放到堆的最后一个, 堆-1, 继续调整排序for end in range(len(arr) -1, 0, -1):arr[0], arr[end] = arr[end], arr[0]siftdown(arr, 0, end - 1)

验证堆排序算法:

def main():array = [16,10,15,8,9,12,14,6]print("原数组: ",array)heap_sort(array)print("排序后数组: ",array)
if __name__ == "__main__":main()

执行结果:

总结

一般需要排序的数据都存放于数组中,而堆排序使用了堆这个数据结构,相当于将堆嵌入到包含了序列的数组中,然后通过交换数组中的数据来进行排序,可以说是强行在数组中使用了堆结构。堆排序一开始需要将 n 个数据存进堆里,所需要时间为 O(nlogn)。排序过程中,堆从空堆的状态开始,逐渐被数据填满,由于堆的高度小于 log2n,所以插入 1 个数据所需要的时间是 O(logn)。每轮取出最大的数据并重构堆需要的时间为 O(logn),由于总共 n 轮,因此重构后排序的时间也是 O(nlogn)。故整体看来堆排序的时间复杂度为 O(nlogn),虽然堆排序整体运行效率不错,但是堆这个结构相对复杂,所以实现起来也较为困难。

【算法实践】他山之石, 可以攻玉 -- 利用完全二叉树快速实现堆排序相关推荐

  1. 他山之石可以攻玉, 不可不读的阿里云原生中间件行业案例与实践集锦

    简介:阿里云原生中间件行业案例与实践集锦 1.[在线教育行业]Timing App的Serverless实践案例 在用户.流量爆发式增长背景下,Timing App面临着四大挑战: 系统稳定性差.产品 ...

  2. 数据中心节能专题—他山之石可以攻玉

    电机是耗电量最大的单种类设备.根据国际能源署最近的一项调查,电机耗电量占据工业领域耗电量的大约三分之二,如上所述,占大约 46% 的全球耗电量. 随着数字化生活的推进,数据中心已成为不疏于工业企业的用 ...

  3. 一探B站后台架构, 他山之石, 何以攻玉? -- 仅从一个一线Golang开发者的角度谈B站4.22代码

    4月22日, B站部分后台源代码因为某愤怒的员工, 被上传至Github. 本文我们不讨论安全, 法律, 去恶意攻击或者获利是违法的! 我们工作时也要注意代码安全), 我仅从开发者的角度谈谈, 这份代 ...

  4. 个人第一次作业——“他山之石,可以攻玉”

    --------------------------- 这个作业属于哪个课程| <课程的链接> ---- | ---- 这个作业要求在哪里| <作业的要求> 我在这个课程的目标 ...

  5. 【IT职场生存手册】他山之石,可以攻玉【51CTO技术论坛】

    http://bbs.51cto.com [IT职场生存手册]他山之石,可以攻玉         人生的每条路对于我们都是新的,因为不能重新来过.所以会有很多困惑.疑虑,就想混在IT职场的人们,常常看 ...

  6. 新颖性搜索(Novelty Search,NS)算法实践——利用NS算法解决迷宫导航问题

    新颖性搜索(Novelty Search,NS)算法实践--利用NS算法解决迷宫导航问题 新颖性搜索(Novelty Search,NS)算法介绍 NS实现基础 NovItem NoveltyArch ...

  7. 他山之石、可以攻玉 - 我的2015年总结

    他山之石.可以攻玉- 我的2015年总结 本来打算年前写个总结的,没办法最近事情比较多,拖到年后了,2015年自己经历事情 真的是挺多的,无论在工作还是生活还是工作,个人发展方面都有一些新的变换. 关 ...

  8. 他山之石,可以攻玉, 改造fasthttp实现高性能网络通信

    前言 如果朋友看过在下上一篇文章<boot4go-gateway和nginx的性能测试大PK>,能在反向代理的性能PK中完胜Nginx的Gateway,是使用GO语言在基于比Go的标准ht ...

  9. 它山之石可以攻玉,AP计算机AP微积分同时取得满分------肺腑经验,以资借鉴!

    一开始我是在学校学了A level计算机,但老师没讲清楚就经常一脸懵.后来上了林振营老师的AP 计算机课程,林老师讲课由浅入深,条理清晰,令我茅塞顿开,用几节课就让我明白了学校老师讲了一个月也没讲明白 ...

最新文章

  1. python动态规划组合数最大_编写用动态规划法求组合数()的算法。
  2. 每日Ubuntu小技巧:一款轻量级的Email阅读器Geary
  3. 參加microsoft主管信息論壇
  4. IDEA Unmapped Spring configuration files found.
  5. ffmpeg+rtmp推流/拉流(十)
  6. WebService学习总结(6)——WebService常用接口
  7. bt种子爬虫程序和种子解析(大蟒蛇语言编写)
  8. 微信小程序毕业设计、基于微信棋牌室管理小程序毕设
  9. 数字信号处理——时域采样和频域采样(matlab)
  10. 基于Java Swing五子棋小游戏设计和实现
  11. 计算机技能培训课程感悟,计算机技能培训心得.doc
  12. 大数据学习笔记:聚类分析
  13. WIN10阻止OA附件打开
  14. 车牌识别,移植到android系统
  15. java 自动识别并解压HDFS压缩文件
  16. eclipse如何导入jdk包
  17. 黑马大数据分析课程---1、大数据分析介绍
  18. 打造你自己的vim--如何配置vim
  19. 语法体系:五大基本句型day1
  20. DDD 中的CQRS(命令查询职责分离)架构模型有哪些?

热门文章

  1. 计算机ms高级应用科目一 科目二考什么,驾考提前知 | 科目一、科目二、科目三、科目四都考什么?...
  2. 排序(使用插入法对数组元素从小到大排序)
  3. 如何判断如何判断RS232线是直连还是交叉连线
  4. 用SDK包开发K66FX18学习笔记(2)
  5. Macbook Pro 启动Win7的过程中黑屏(black screen)
  6. 截屏、文字提取一气呵成,超实用 OCR 开源小工具
  7. xml和html的区别和联系
  8. idea中为啥要用maven
  9. java斜体_设置标签字体用粗体和斜体
  10. cvte在线笔试 android,CVTE在线笔试