堆是一种特殊的树形数据结构,通常提到的堆都是指一棵完全二叉树,根节点的值小于(或大于)两个子节点的值,同时,根节点的两个子树也分别是一个堆。
      堆排序是一种树形选择排序,在排序过程中,将R[1…n]看作一棵完全二叉树的顺序存储结构,利用完全二叉树中父节点和子节点之间的关系来选择最小的元素。

排序思路

堆排序的思想是:对于给定的n个记录,初始时把这些记录看作是一棵顺序存储的完全二叉树,然后将其调整为一个大顶堆(或小顶堆),然后将堆的最后一个元素与堆顶元素(即二叉树的根节点)交换,堆的最后一个元素即为最大记录(或最小记录);接着将前n-1个记录重新调整,再交换最后一个元素与堆顶元素得到次大的记录;重复该过程直到调整的堆中只有一个元素为止。

为了更直接的描述堆排序的思路,下面举一个例子:
现在有一组记录如下,使用堆排序对下面的记录进行排序,这里以最小堆为例。

第一步:构建堆
堆是一棵完全二叉树,所以首先要构造一颗完全二叉树,如下:

然后,将该树调整为最小堆,调整的过程后面再说,这里先说明堆排序的过程,调整好的堆如下:

可以看到,此时堆顶的元素即为最小记录,且每一个子树均满足:根节点的值小于左右子节点的值。

第二步:交换堆顶元素与最后一个元素,重新调整堆
交换堆顶元素与最后一个元素:

重新调整堆:

到这里,就完成了一个元素的排序,接下来就是对除去这一个元素,剩下的树重复第二个步骤,这里用蓝色表示已经排好序的元素,也就是除去的元素。
交换堆顶元素与最后一个元素:

重新调整堆:

到这里,就完成了两个元素的排序,接下来就是对除去这两个元素,剩下的树重复第二个步骤,这里用蓝色表示已经排好序的元素,也就是除去的元素。
交换堆顶元素与最后一个元素:

重新调整堆:

到这里,就完成了三个元素的排序,接下来就是对除去这三个元素,剩下的树重复第二个步骤,直到最后剩下的树中只有一个节点为止。
排序完成的树结构如下:


代码实现

了解了堆排序的思想,那么用代码来实现就不难了,主要分为三个步骤:
(1)构建堆;
(2)交换堆顶元素与最后一个元素;
(3)重新调整堆

(1)构建堆

构建堆实际上还是一个调整堆的过程,只是这一步需要对每一个节点都进行调整,使得每一个节点都满足“根节点小于左右子节点的值”这一条件。这样最后的形成的堆才是一个最小堆。
所以构建堆就是从最后一个节点遍历到根节点,堆每一个节点进行调整。

(2)交换堆顶元素与最后一个元素

这个比较简单,没什么可说的

(3)重新调整堆

这里的调整堆和构建堆不同的地方在于,这里的重新调整堆只需要调整根节点即可,而不是像构建对那样需要对全部节点进行调整。为什么呢?
因为在构建堆的时候已经调整了全部节点,每个节点都满足最小堆的条件:根节点小于左右子节点的值。
而(2)的步骤只修改了根节点的值,所以只需要调整根节点即可。


堆排序最关键的代码在于调整堆这部分的代码
完整代码如下:

public class HeapSort {public static void main(String[] args) {int a[] = { 5, 4, 9, 8, 7, 6, 0, 1, 3, 2 };myHeapSort(a);for (int i : a)System.out.print(i + " ");}public static void myHeapSort(int[] arr) {int i;int len = arr.length;// 构建一个最小堆for (i = len / 2 - 1; i >= 0; i--) {adjustment(arr, i, len);}// 每次将顶点与最后一个节点交换,然后重新调整顶点即可for (i = len - 1; i >= 0; i--) {int tmp = arr[0];arr[0] = arr[i];arr[i] = tmp;adjustment(arr, 0, i);}}public static void adjustment(int[] arr, int pos, int len) {int child = 2 * pos + 1;// 若pos的右节点存在,则child指向左右节点值较小的那个节点if (child + 1 < len && arr[child] > arr[child + 1]) {child++;}// 将pos节点的值取其与子节点中的最小值,然后继续调整if (child < len && arr[pos] > arr[child]) {int tmp = arr[pos];arr[pos] = arr[child];arr[child] = tmp;adjustment(arr, child, len);}}
}

main方法调用myHeapSort方法,传入一个数组,也就是待排序的记录集合。

// 构建一个最小堆
for (i = len / 2 - 1; i >= 0; i--) {adjustment(arr, i, len);
}

这几行代码就是构建堆的代码,遍历每一个节点,对每一个节点进行调整。
为什么i从len / 2 - 1开始呢?因为从这个节点开始,才至少有一个左右节点,比它大的节点都没有左右节点,也就无需调整。

// 每次将顶点与最后一个节点交换,然后重新调整顶点即可
for (i = len - 1; i >= 0; i--) {int tmp = arr[0];arr[0] = arr[i];arr[i] = tmp;adjustment(arr, 0, i);
}

这部分代码就是每次交换堆顶元素与最后一个元素,然后重新调整堆顶元素。

adjustment方法就是对执行的节点进行调整。要记住,如果某个节点调整的时候与左右节点进行值的交换,那么要继续调整交换了值的那个子节点,直到没有交换发生为止,所以使用了递归完成。

堆排序之JAVA实现相关推荐

  1. 堆排序算法java左程云_堆排序算法以及JAVA实现

    堆的定义如下: n个元素的序列{k0,k1,...,ki,-,k(n-1)}当且仅当满足下关系时,称之为堆. " ki<=k2i,ki<=k2i+1;或ki>=k2i,ki ...

  2. 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)

    转载:http://blog.csdn.net/pzhtpf/article/details/7559943 3.简单选择排序 (1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换 ...

  3. 排序算法(二)--堆排序(JAVA)

    堆的一个很重要的应用就是堆排序,和快速排序一样,堆排序的时间复杂度也是O(NlgN) 堆排序的实现思路一: 1.创建小根堆 2.每次删除顶部元素并将顶部元素输出(删除的函数中有调整的过程,每次调整) ...

  4. 插入,冒泡,选择,快速,归并,堆排序,java 泛型实现

    2019独角兽企业重金招聘Python工程师标准>>> package keepthinker.sort;import java.util.ArrayList; import jav ...

  5. 排序系列 之 堆排序算法 —— Java实现

       基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...

  6. 利用java的PriorityQueue类实现堆排序(java实现)

    堆排序 堆排序 实现代码 优化 堆排序 堆排序:利用自己写的最大堆或者java库中的PriorityQueue优先队列类,可以进行堆排序.把数组每个数放进堆里面,PriorityQueue优先队列类默 ...

  7. 优先队列-二叉堆-堆排序原理-Java相关API

    完全二叉树概念 除了最后一层,前面所有层都是满的 最后一层是从左到右 是一个二叉树 堆 满足完全二叉树 父节点存储的元素比子节点大 上浮 不符合堆规则的节点,与父节点交换 直到上浮到符合为止 下沉 不 ...

  8. 堆排序(JAVA版)

    堆排序原理就不解释了,大家可以自行查找,建议大家阅读<算法导论>第六章堆排序,很详细哦,在这里直接把源码贴出来. 如果大家想了解另外两种牛掰的排序算法,请猛戳下面链接 快速排序 归并排序 ...

  9. 堆排序的java实现_堆排序(java实现)

    public class heapSort01 { //构建大根堆:将array看成完全二叉树的顺序存储结构 private int[] buildMaxHeap(int[] array){ //从最 ...

最新文章

  1. vscode 搭建go开发环境的13个插件的安装
  2. pythonsorted_[转].Python中sorted函数的用法
  3. 什么是java常量?
  4. [html] 怎样避免让用户看到长时间的白屏?
  5. PHP企业网站源码-稻草人PHP系统源码v1.0.3
  6. C#.Net工作笔记009---c#中Yield Return语法的作用和好处
  7. ios沙盒机制与文件操作
  8. windows下WDK创建免费的测试证书,并签名windows驱动文件(附带测试效果)
  9. [架构之路-47]:目标系统 - 系统软件 - Linux OS硬件设备驱动 - CPU内存管理单元MMU、DMA与IO内存管理单元IOMMU
  10. linux 进程killed_linux下运行Gaussian09进程被killed
  11. 曹鹏CSS视频教程 编程之邦
  12. Python正则表达式(网址正则/超链接正则)
  13. Android游戏开发+实战开发教程视频
  14. 英语单词 One 个人 2. 出生和死亡
  15. 最窄770px最宽1024px经典布局
  16. 如何使用电脑将图片进行压缩?图片压缩软件怎么操作?
  17. 【Android,Kotlin】No type arguments expected for class Call
  18. flink onTimer定时器实现定时需求
  19. WGCNA | 值得你深入学习的生信分析方法!~(网状分析-第一步-数据整理)
  20. 一种简单的地图聚合算法

热门文章

  1. 公司到底是怎么看我们的……
  2. 学python对工作有什么帮助_学python有什么好处 学好了能干什么
  3. 2. Packet crafting tools (封包工具 6个)
  4. Eclipse中建多层级包时出现的问题
  5. python selenium 元素定位和页面操作
  6. (java)scanner.next()与scanner.nextLine()的区别
  7. python环境下paillier同态密码库踩坑记录
  8. JavaScript高级教程-代理与反射
  9. 数据通信与网络(五)
  10. CK-S650系列HDX半双工RF玻璃管转发器阅读器|读写器之SECS协议验证软件使用说明