排序算法总结之堆排序
一,堆排序介绍
堆是一个优先级队列,对于大顶堆而言,堆顶元素的权值最大。将 待排序的数组 建堆,然后不断地删除堆顶元素,就实现了排序。关于堆,参考:数据结构--堆的实现之深入分析
下面的堆排序算法将数组中的元素从小到大排序,用大顶堆来实现。
二,堆排序算法分析
现给定了一维数组,需要将数组中的元素使用堆排序。首先,得创建一个堆,可以在这个给定的一维数组上建堆。 对N个元素 建堆的时间复杂度为O(N)
堆排序具体的细节实现有两种方式:一种方式是将堆顶元素删除后,放到一个辅助数组中,然后进行堆调整使之成为一个新堆。接下来,继续删除堆顶元素,直至将堆中所有的元素都出堆,此时排序完成。这种方式需要一个额外的辅助空间O(N)
另一种方式是:将每次删除的堆顶元素放到数组的末尾。因为,对于堆的基本操作 delMin/delMax 而言(delMin针对的是小顶堆,delMax针对的是大顶堆,原理一样)是将堆中的最后一个元素替换堆顶元素,然后向下进行堆调整。因此,可以利用这个特点将每次删除的堆顶元素保存在数组末尾,当所有的元素都出堆后,数组就排好序了。这种方式不需要额外的辅助空间,空间复杂度为O(1)
三,堆排序算法实现
1 public class HeapSort { 2 3 public static <T extends Comparable<? super T>> void heapSort(T[] arr){ 4 //build heap 5 for(int i = arr.length/2 - 1; i >= 0; i--) 6 percDown(arr, i, arr.length); 7 8 9 for(int i = arr.length - 1; i >= 0; i--) 10 { 11 swapReference(arr, 0, i);//delete Max 12 13 percDown(arr, 0, i);// 从根开始向下堆调整 14 } 15 } 16 17 private static <T extends Comparable<? super T>> void swapReference(T[] arr, int from, int to){ 18 T tmp; 19 tmp = arr[from]; 20 arr[from] = arr[to]; 21 arr[to] = tmp; 22 } 23 24 //求解 i 的左孩子 25 private static int leftChild(int i){ 26 return 2*i + 1; 27 } 28 29 /** 30 * 31 * @param arr 存储堆的一维数组 32 * @param i 从 i 位置开始进行向下堆调整 33 * @param n 堆中元素的个数(不是数组的长度) 34 */ 35 private static <T extends Comparable<? super T>> void percDown(T[] arr, int i, int n){ 36 int child; 37 T tmp;//保存当前待调整的结点,当找到了合适的位置后,需要将之放入到合适位置,以保持堆序性质 38 39 for(tmp = arr[i]; leftChild(i) < n; i = child) 40 { 41 child = leftChild(i); 42 if(child != n-1 && arr[child].compareTo(arr[child+1]) < 0) 43 child++;//右孩子更大 44 if(tmp.compareTo(arr[child]) < 0) 45 arr[i] = arr[child];//父节点下移 46 else 47 break;//父节点比左右孩子都大时,不需要再向下移动了 48 } 49 arr[i] = tmp;//将节点放入合适的位置 50 } 51 52 //for test purpose 53 public static void main(String[] args) { 54 Integer[] arr = {31,41,59,26,53,58,97}; 55 heapSort(arr); 56 for (Integer i : arr) { 57 System.out.print(i + " "); 58 } 59 } 60 }
有几个细节地方解释一下:
①在第3行的heapSort方法中,第5-6行是建堆操作,因为数组中的元素是从下标0开始存储的,故最后一个非叶子结点的下标为:arr.length/2 - 1
②第9-14行是进行堆排序的操作。swapReference方法相当于删除堆顶元素,因为它把堆顶元素交换到数组的末尾去了,此时堆顶元素不再是最大值(大顶堆)。删除了堆顶元素之后,就要进行堆调整以保持堆序性质,故percDown方法 完成向下进行堆调整的功能。
③在堆调整的过程中,需要求解某个结点的左 右孩子结点的位置。故有一个leftChild方法用来求解左孩子的位置(注意元素是从数组下标0开始存储的)
④percDown方法实现向下的堆调整功能。第37行 tmp 变量 保存当前待调整的结点,当找到了合适的位置后,需要将之放入到合适位置,以保持堆序性质。对于建堆而言,待调整的结点是从 非叶结点 开始,直至根的那些结点。对于删除堆顶元素而言,则总是从堆顶元素起开始调整(待调整的结点是根)
⑤第39行的for循环实现得非常巧妙,首先tmp保存当前待调整的结点 arr[i],然后判断 arr[i] 是否有左孩子,如果有左孩子的话,又在第42行的if语句中判断它是否还有右孩子(child != n-1),然后左右孩子进行比较,child记录下权值大的那个孩子。
⑥第44-45行的if语句完成的功能是:将权值大的孩子与父结点比较,如果父结点的权值小,则需要将那个较大的孩子上移到父结点的位置(也相当于父结点下移到孩子的位置)
如果父结点的权值大,已经找到了合适的位置了。说明不需要再进行堆调整了,执行else break;
⑦第49行,就待调整的结点入到到合适的位置i处。整个过程并没有用交换操作,而是用的是赋值操作来隐式地实现了交换操作完成的功能,这是一个优化。
四,堆排序算法复杂度分析
对N个元素建堆的时间复杂度为O(N),删除堆顶元素的时间复杂度为O(logN),尽管随着元素的不断删除,堆的调度越来越小,但是总的而言,删除堆所有元素的时间复杂度为O(NlogN)
故堆排序的时间复杂度为O(NlogN),空间复杂度为O(1)
其实,堆排序是一个非常稳定的算法,最坏和平均情况下的时间复杂度都为O(NlogN)
此外,对于堆排序而言,数据的初始顺序对它的复杂度没有影响。不管数组初始时就是有序的还是逆序的,它都会先建堆,变成了堆序的性质。
五,参考资料
排序算法总结之插入排序
排序算法总结之快速排序
排序算法总结之归并排序
各种排序算法的总结
排序算法总结之堆排序相关推荐
- js排序算法详解-堆排序
全栈工程师开发手册 (作者:栾鹏) js系列教程5-数据结构和算法全解 js排序算法详解-堆排序 这种排序方式呢,理论性太强,看动图的时候满脸写着懵逼,多看几遍似乎明白了编者的意图,但是要把这种理论的 ...
- 3.图解排序算法(三)之堆排序
作者: dreamcatcher-cx 出处: http://www.cnblogs.com/chengxiao/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在页面明显位 ...
- 经典排序算法之:堆排序
背景及原理 1991年的计算机先驱奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同发明了著名的堆排序算法( Hea ...
- 冒泡和快速排序的时间复杂度_java 八大排序算法 冒泡排序 快速排序 堆排序 归并排序 等...
八大排序算法 一.直接插入 1.基本思路 在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的.如此反复循环 ...
- 排序算法笔记:堆排序 HeapSort in java
2019独角兽企业重金招聘Python工程师标准>>> /*** 堆排序* 简述:* 首先使用建立最大堆的算法建立好最大堆,然后将堆顶元素(最大值)与最后一个值交换,同时使得堆的长度 ...
- java heapsort_排序算法笔记:堆排序 HeapSort in java
/** * 堆排序 * 简述: * 首先使用建立最大堆的算法建立好最大堆,然后将堆顶元素(最大值)与最后一个值交换,同时使得堆的长度减小1 ,调用保持最大堆性质的算法调整,使得堆顶元素成为最大值,此时 ...
- 排序算法三:堆排序基本原理以及Python实现
1. 基本原理 堆排序就是利用堆的特性进行一个无序序列的排序工作. 堆的特点 堆分为最大堆和最小堆,其实就是完全二叉树. 最大堆要求节点的元素都要不小于其孩子 最小堆要求节点元素都不大于其左右孩子. ...
- Python 一网打尽<排序算法>之堆排序算法中的树
本文从树数据结构说到二叉堆数据结构,再使用二叉堆的有序性对无序数列排序. 1. 树 树是最基本的数据结构,可以用树映射现实世界中一对多的群体关系.如公司的组织结构.网页中标签之间的关系.操作系统中文件 ...
- Java数据结构与排序算法——堆和堆排序
//================================================= // File Name : Heap_demo //--------------------- ...
最新文章
- 成功有感之给年轻人的10个忠告
- 官宣,11月8号,.NET6+64位VS璀璨面世!
- HTML5中的本地数据库-Web SQL Database
- html 网页制作标签,html网页制作标签最全版.doc
- 郝蕾怒骂河南人---江湖再起风云,网络哪里有净土
- mysql检查文件_如何检查和修复MySQL数据文件?
- 【opencv学习】图像特征检测
- python如何在没有环境的电脑上执行_没安装python的电脑可以运行python写的程序吗 python语言编写的程...
- [产品相关] A/B测试终极指南(翻译)
- python数据类型_Python数据类型
- JAVA里plain_Java中POJO及其细分XO、DAO的概念
- 数据结构实验1-线性表的顺序实现
- 微信小程序使用字体图标
- 标杆企业华为背景——张蕾老师
- matlab导入vgg16,简单导入VGG16
- 2019中国互联网应用基本发展状况
- Python#Typora-Python笔记
- 王者荣耀上官婉儿的语录
- Playwright之初体验
- java 在线excel_Java实现最简单的在线打开保存Excel文件
热门文章
- ant学习笔记之(ant执行命令的详细参数和Ant自带的系统属性)
- Field types
- 2010.10.30 OA 项目组一周工作报告
- tf.matmul / tf.multiply
- Room Database完全使用手册
- Kafka配置SSL(云环境)
- Hibernate- 子查询
- 数据处理系列(四) 安装Elasticsearch用以存储和查询数据
- [Django](1093, quot;You can#39;t specify target table #39;fee_details_invoices#39; for update in...
- My deep learning reading list