排序算法相必大家都见过很多种,例如快速排序、归并排序、冒泡排序等等。今天,我们就来简单讲讲堆排序

在上一篇中,我们讲解了二叉堆,今天的堆排序算法主要就是依赖于二叉堆来完成的,不清楚二叉堆是什么鬼的,可以看下:

【算法与数据结构】二叉堆是什么鬼?

                                                          用辅助数组来实现堆排序算法

假如给你一个二叉堆,根据二叉堆的特性,你会怎么使用二叉堆来实现堆排序呢?

我们都知道,二叉堆有一个很特殊的节点 —- 堆顶,堆顶要嘛是所有节点的最大元素,要嘛是最小元素,这主要取决于这个二叉堆是最小堆还是最大堆

今天,我们暂且选择以最小堆来作为例子。

基于堆顶这个特点,我们就可以来实现我们的堆排序了。

大家看下面一个例子:

对于一个如图有10个节点元素的二叉堆:

我们把堆顶这个节点删除,然后把删除的节点放在一个辅助数组help里(黑色的节点表示已经被删除没用的点)。

显然,这个被删除的节点,是堆中值最小的节点。接下来,我们继续删除二叉堆的堆顶,然后把删除的元素还是存放在help数组里。

显然,第二次删除的节点,是原始二叉堆中的第二小节点。继续重复删除堆顶。

继续连续6次删除堆顶,把删除的节点一次放入help数组。

二叉堆中只剩最后一个节点了,这个节点同时也是原始二叉堆中的最大节点,把这个节点继续删除了,还是放入help数组里。

此时,二叉堆的元素被删除光了,观察一下help数组。这是一个有序的数组,实际上,通过从二叉堆的堆顶逐个取出最小值,存放在另一个辅助的数组里,当二叉堆被取光之时,我们就完成了一次堆排序了。

                                                                          其实无需辅助数组

在上面的堆排序过程中,我们使用了一个辅助数组help。可事实上,我们真的需要辅助数组吗?

上篇讲二叉堆的时候,我们说过。二叉堆在实现的时候,是采取数组的形式来存储的。

从二叉堆中删除一个元素,为了充分利用空间,其实我们是可以把删除的元素直接存放在二叉堆的最后一个元素那里的。例如:

删除堆顶,把删除的元素放在最后一个元素。

节点,把删除的元素放在最后第二个位置

继续删除

以此类推….

这样,对于一个含有n个元素的二叉堆,经过n-1(不用删除n次)次删除之后,这个数组就是一个有序数组了。

所以,给你一个无序的数组,我们需要把这个数组构建成二叉堆,然后在通过堆顶逐个删除的方式来实现堆排序。

其实,也不算是删除了,相当于是把堆顶的元素与堆尾部在交换位置,然后在通过下沉的方式,把二叉树恢复成二叉堆。

代码如下:

对于堆的时间复杂度,我就直接给出了,有兴趣的可以自己推理下,还是不难的。堆的时间复杂度是 O (nlogn)。空间复杂度是 O(1)。

这里可能大家会问,堆排序的时间复杂度是O (nlogn),像快速排序,归并排序的时间复杂度也是 O(nlogn),那我在使用的时候该如何选择呢?

这里说明一下:快速排序是平均复杂度 O(logn),实际上,快速排序的最坏时间复杂度是O(n^2。),而像归并排序,堆排序,都稳定在O(nlogn)

我给出一个问题,例如给你一个拥有n个元素的无序数组,要你找出第 k 个大的数,那么你会选择哪种排序呢?

显然在这个问题中,选用堆排序是最好的,我们不用把数组全部排序,只需要排序到前k个数就可以了。至于代码如何实现,这个我就不给代码了,大家可以动手敲一敲。

public class HeapSort {/**下沉操作,执行删除操作相当于把最后一个元素赋给根元素之后,然后对根元素执行下沉操作*@param arr*@param parent 要下沉元素的下标*@param length 数组长度*/public static int[] downAdjust(int[] arr, int parent, int length) {//临时保证要下沉的元素int temp = arr[parent];//定位左孩子节点位置int child = 2 * parent + 1;//开始下沉while (child < length) {//如果右孩子节点比左孩子小,则定位到右孩子if (child + 1 < length && arr[child] > arr[child + 1]) {child++;}//如果父节点比孩子节点小或等于,则下沉结束if (temp <= arr[child]) break;//单向赋值arr[parent] = arr[child];parent = child;child = 2 * parent + 1;}arr[parent] = temp;return arr;}//堆排序public static int[] heapSort(int[] arr, int length) {//构建二叉堆for (int i = (length - 2) / 2; i >= 0; i--) {arr = downAdjust(arr, i, length);}//进行堆排序for (int i = length - 1; i >= 1; i--) {//把堆顶的元素与最后一个元素交换int temp = arr[i];arr[i] = arr[0];arr[0] = temp;//下沉调整arr = downAdjust(arr, 0, i);}return arr;}//测试public static void main(String[] args) {int[] arr = new int[]{1, 3, 5, 2, 0, 10, 6};System.out.println(Arrays.toString(arr));arr = heapSort(arr, arr.length);System.out.println(Arrays.toString(arr));}
}

参考链接:https://mp.weixin.qq.com/s?__biz=MzUxNzg0MDc1Mg==&mid=2247484222&idx=1&sn=2a3d3f0e95df9d1fdcc2e21123721e66&chksm=f9934921cee4c037fe37eb9a27454f095376117985187867b09bd95b564e4941956ead73ed93&scene=21#wechat_redirect

【算法与数据结构】堆排序是什么鬼?相关推荐

  1. Caché 算法与数据结构

    第一章 Caché 算法与数据结构 基础和概念 ☆☆☆☆☆ 第二章 Caché 算法与数据结构 数组原理 ☆☆☆☆☆ 第三章 Caché 算法与数据结构 链表原理 ☆☆☆☆☆ 第四章 Caché 算法 ...

  2. 浅谈算法和数据结构: 五 优先级队列与堆排序

    原文:浅谈算法和数据结构: 五 优先级队列与堆排序 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象.最简单的一个例子就是,在手机上玩游戏 ...

  3. 维基百科上的算法和数据结构链接很强大

    突然发现维基百科上的算法和数据结构比百度百科强多啦,图文并茂. 其实这个网站不错:http://www.sorting-algorithms.com 冒泡排序: bubble冒泡的意思 http:// ...

  4. GitHub标星3w+的项目,全面了解算法和数据结构知识

    作者 | 程序员小吴 来源 | 五分钟学算法(ID: CXYxiaowu) 导语:今天分享一个开源项目,里面汇总了程序员技术面试时需要了解的算法和数据结构知识,并且还提供了相应的代码,目前 GitHu ...

  5. java优先队列的入队函数,算法与数据结构番外(1):优先队列

    这是算法与数据结构番外系列的第一篇,这个系列未来的主要内容是补充一些与算法与数据结构相关的知识,这些知识比较零碎,同时也与正传关系密切,往往需要阅读了正传的相关内容以后,才能较好的理解这部分内容.如果 ...

  6. Python入门篇-数据结构堆排序Heap Sort

    Python入门篇-数据结构堆排序Heap Sort 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.堆Heap 堆是一个完全二叉树每个非叶子结点都要大于或者等于其左右孩子结点的 ...

  7. 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...

  8. 算法与数据结构c语言版PPT,C语言算法与数据结构.ppt

    C语言算法与数据结构.ppt 第十二章 算法与数据结构12.1 算法的基本概念,该节知识点所占试题比重为12,属于重点考查对象,基本上每次必考,主要考查算法的定义和对算法复杂度的理解.历次试题分值在0 ...

  9. java堆算法_用Java写算法之七:堆排序

    堆是数据结构中的一种重要结构,了解了"堆"的概念和操作,可以快速掌握堆排序. 堆的概念 堆是一种特殊的完全二叉树(complete binary tree).如果一棵完全二叉树的所 ...

最新文章

  1. 抖音爬取粉丝用户列表_抖音分享页用户信息爬取
  2. docker 连接容器
  3. 【numpy】np.genfromtxt非常的慢,并且需要读取文件的10倍内存
  4. m_Orchestrate learning system---六、善用组件插件的好处是什么
  5. Javascript中的0,false,null,undefined,空字符串对比
  6. codeblocks调试窗口字体大小以及修改主题
  7. Jenkins的maven工程打包的时候怎么指定不同环境的配置文件
  8. 用dl元素编辑html个人信息,html dl dt dd标签元素语法结构与使用
  9. 服务器硬盘数据备份到nas,群晖NAS教程第五节:如何备份 Synology NAS
  10. Ubuntu安装vmPlayer
  11. 如何用流程图描述算法?
  12. 《SEM长尾搜索营销策略解密》一一1.5 互联网时代,世界不再匮乏
  13. PoE供电概述:PoE交换机是如何进行供电的?
  14. 一文带你学习跨站点请求伪造(CSRF)
  15. NuttX的学习笔记 9
  16. Debian etch 基本系统 initial ram disk 的分析
  17. 51Nod 1048 1383 整数分解为2的幂
  18. 哈工大计算机学院专业成绩公示,哈工大2009计算机学院录取名单及初试复试成绩排名...
  19. MATLAB的图像显示方法
  20. 燕麦云何洋开讲丨真假海盗?黑客杠上好莱坞,还要把电影变成现实

热门文章

  1. Effective Java之抛出与抽象相应的异常(六十一)
  2. 安装Mongodb并解决用户授权问题
  3. poj 3233 Matrix Power Series
  4. 【测试点分析】1035 Password (20 分)
  5. linux jrdmm 命令 局部 编译,Cgminer-4.10.0 Linux 挖矿
  6. linux内核支持utf8,Linux对非UTF-8中文编码的支持
  7. python 输出引号_python输出字符串单双引号如何选择
  8. _效率高的Linux管理员都会的10个关键技巧
  9. 10通信端口感叹号_工程现场通信总线布线、压接规范
  10. php 数组的格式,PHP文件格式数组