热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

堆排序时间复杂度_再也不怕面试官问我堆排序了

前提面试中经常会遇到对堆排序的考察,比如阿里巴巴2016研发工程师笔试题之一:将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列&

前提

面试中经常会遇到对堆排序的考察,比如阿里巴巴2016研发工程师笔试题之一:

将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在第一轮排序结束之后,数组的顺序是_____。

不了解堆排序的小伙伴此时就会比较尴尬了。

1c2f5c27f3f65939579f733727818936.png

那么到底什么是堆排序呢?它的原理是什么?代码又怎么实现呢?

什么是堆

在介绍堆排序之前,先让我们来了解一下堆及其属性:

堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

87ca269b373fb25ad82816c54562d9b4.png
818319feae50239a950f630fd9bf50c0.png

堆是非线性数据结构,相当于一维数组,有两个直接后继。

堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。

(ki <&#61; k2i,ki <&#61; k2i&#43;1)或者(ki >&#61; k2i,ki >&#61; k2i&#43;1), (i &#61; 1,2,3,4...n/2)

若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树&#xff0c;则堆的含义表明&#xff0c;完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此&#xff0c;若序列{k1,k2,…,kn}是堆&#xff0c;则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

堆排序

堆排序(Heapsort)是利用堆这种数据结构而设计的一种排序算法&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。堆排序的流程&#xff1a;

  1. 将无序序列构建成一个堆&#xff0c;根据升序降序需求选择大顶堆或小顶堆;
  2. 将堆顶元素与末尾元素交换&#xff0c;将最大元素"沉"到数组末端;
  3. 重新调整结构&#xff0c;使其满足堆定义&#xff0c;然后继续交换堆顶元素与当前末尾元素&#xff0c;反复执行1-2步骤&#xff0c;直到整个序列有序。

动图演示
ec0c0873601b60216db353e604ab4f62.gif

代码实现

void adjuctHeap(int i, int arr[], int count) {int tmp;int max;// 条件判断检测是否到了叶子节点while (i <&#61; count / 2 - 1) {//父节点索引为i时&#xff0c;左子节点下标为2i&#43;1&#xff0c;右子节点下标为2i&#43;2//总数为偶数时&#xff0c;最后一个父节点没有右子节点&#xff0c;此时tmp置为0tmp &#61; 2 * i &#43; 2 >&#61; count ? 0 : arr[2 * i &#43; 2];//max值&#xff1a;左右子节点中更大的那个节点的下标max &#61; arr[2 * i &#43; 1] >&#61; tmp ? 2 * i &#43; 1 : 2 * i &#43; 2;//如果子节点比父节点大&#xff0c;则交换父子节点的值if (arr[max] > arr[i]){tmp &#61; arr[max];arr[max] &#61; arr[i];arr[i] &#61; tmp;//父子节点交换完以后&#xff0c;要判断新的子节点下面是否也有子节点&#xff0c;如果有的话也要进行相同的调整i &#61; max;}elsebreak;}}void heapSort(int arr[], int count) {int i;int tmp;//停留在构造成功大根堆的前一步。 count / 2 - 1 表示倒数第一个非叶子节点for (i &#61; count / 2 - 1; i > 0; i--) adjuctHeap(i, arr, count);while (count > 1) {adjuctHeap(0, arr, count); //构造大根堆tmp &#61; arr[0]; //取出第一个值&#xff0c;及最大值arr[0] &#61; arr[count - 1]; //调整最大值到最后的位置arr[count - 1] &#61; tmp;count--; //末尾往前移动一位}}

平均时间上&#xff0c;堆排序的时间常数比快排要大一些&#xff0c;因此通常会慢一些&#xff0c;但是堆排序最差时间也是O(nlogn)的&#xff0c;这点比快排好。

结束语

至此&#xff0c;十种常见的排序算法都已经整理完毕&#xff0c;如果中间有什么写错或者笔误的地方还劳烦大家批评指正&#xff0c;共同进步。

1ce50b872393266c83f54351af0f9b17.png



推荐阅读
  • 深入解析十大经典排序算法:动画演示、原理分析与代码实现
    本文深入探讨了十种经典的排序算法,不仅通过动画直观展示了每种算法的运行过程,还详细解析了其背后的原理与机制,并提供了相应的代码实现,帮助读者全面理解和掌握这些算法的核心要点。 ... [详细]
  • 深入理解二分查找及其应用
    二分查找是一种高效的搜索算法,适用于有序数据集合。其核心思想是通过不断将查找区间缩小一半,直至找到目标元素或区间为空。本文将详细介绍二分查找的基本原理、实现方法以及应用场景的局限性。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 本文总结了《编程珠玑》第12章关于采样问题的算法描述与改进,并提供了详细的编程实践记录。参考了其他博主的总结,链接为:http://blog.csdn.net/neicole/article/details/8518602。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 字节流(InputStream和OutputStream),字节流读写文件,字节流的缓冲区,字节缓冲流
    字节流抽象类InputStream和OutputStream是字节流的顶级父类所有的字节输入流都继承自InputStream,所有的输出流都继承子OutputStreamInput ... [详细]
  • 揭秘腾讯云CynosDB计算层设计优化背后的不为人知的故事与技术细节
    揭秘腾讯云CynosDB计算层设计优化背后的不为人知的故事与技术细节 ... [详细]
  • C++ 进阶:类的内存布局与虚函数类的实现细节
    C++ 进阶:类的内存布局与虚函数类的实现细节 ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • 深入理解Spark框架:RDD核心概念与操作详解
    RDD是Spark框架的核心计算模型,全称为弹性分布式数据集(Resilient Distributed Dataset)。本文详细解析了RDD的基本概念、特性及其在Spark中的关键操作,包括创建、转换和行动操作等,帮助读者深入理解Spark的工作原理和优化策略。通过具体示例和代码片段,进一步阐述了如何高效利用RDD进行大数据处理。 ... [详细]
  • 非计算机专业的朋友如何拿下多个Offer
    大家好,我是归辰。秋招结束后,我已顺利入职,并应公子龙的邀请,分享一些秋招面试的心得体会,希望能帮助到学弟学妹们,让他们在未来的面试中更加顺利。 ... [详细]
  • 本文深入探讨了RecyclerView的缓存与视图复用机制,详细解析了不同类型的缓存及其功能。首先,介绍了屏幕内ViewHolder的Scrap缓存,这是一种最轻量级的缓存方式,旨在提高滚动性能并减少不必要的视图创建。通过分析其设计原理,揭示了Scrap缓存为何能有效提升用户体验。此外,还讨论了其他类型的缓存机制,如RecycledViewPool和ViewCacheExtension,进一步优化了视图复用效率。 ... [详细]
  • openGauss行存储核心架构及其页面组织详解
    行存储的核心架构和页面组织是实现DML操作、可见性判断及多种管理功能的基础。作为基于磁盘的存储引擎,行存储在设计上采用了段页式结构,以优化数据的存储和访问效率。这种设计不仅确保了数据的高效存储,还为行存储的各种高级功能提供了坚实的技术支持。 ... [详细]
  • Java中高级工程师面试必备:JVM核心知识点全面解析
    对于软件开发人员而言,随着技术框架的不断演进和成熟,许多高级功能已经被高度封装,使得初级开发者只需掌握基本用法即可迅速完成项目。然而,对于中高级工程师而言,深入了解Java虚拟机(JVM)的核心知识点是必不可少的。这不仅有助于优化性能和解决复杂问题,还能在面试中脱颖而出。本文将全面解析JVM的关键概念和技术细节,帮助读者全面提升技术水平。 ... [详细]
author-avatar
香樟树1016
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有