一、优先队列(堆)

优先队列包括两种操作的数据结构,插入和删除最小者。

二叉堆的结逻辑结构是一个完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右排列。

二叉堆的物理结构是一个数组,元素存放从下标为1的位置开始。因为这样子实现的话,对于数组中的某一个位置i的元素,在下标不越界的情况下(也就是说该节点有孩子的情况下),其左孩子在位置2i上,有孩子在2i+1上。

二、插入操作

对于堆的插入操作实现,一般使用的策略是上滤(percolate up)策略。上滤操作是只先将要插入的元素插入到最后位置,然后与其父节点比较,如果比父节点还要小,说明该节点放在该位置不符合堆序性质(堆序性质是指一个父节点的值小于两个孩子的值,此时为小堆,如果父节点的值大于两个孩子的值,此时为大堆)。所以将该节点与父节点交换,使符合堆序性质,交换之后,再与新插入元素的父节点比较,知道整个堆符合堆序性质。

三、删除最小者

删除最小者是针对小堆而言的,对小堆来说,最小者始终在根节点,在数组中也就是第一个位置的元素。删除最小者一般使用的策略是下滤(percolate down),下滤是指将根节点删除,然后将最后一个元素的值放到根节点的位置,然后再调整堆,使堆符合堆序性质。

调整堆的过程:

1、先判断其是否有右孩子,如果有右孩子,则必定有左孩子。

判断左右孩子的值是否均大于该节点,如果不是,则与孩子中的最小者交换。以此类推,直到找到结点和合适位置。

2、没有右孩子,只有左孩子

判断右孩子的值是否大于该节点,如果不是,交换两者的位置,以此类推,知道找到结点的合适位置。

3、叶节点,无左右孩子

不用再进行判断,该位置比为该节点的合适位置。

Java源代码如下:

package ljp.sort.heap; public class HeapSort { private int[] list; private int length; // 构造函数,初始化数组 public HeapSort() { list = new int[11]; list[0] = 0; length = 0; for (int i = 1; i < list.length; i++) { list[i] = (int) (Math.random() * 1000); } for (int i = 1; i < list.length; i++) { System.out.print(list[i] + " "); } System.out.println(); System.out.println("建堆过程:"); CreateHeap(); } private void CreateHeap() { // 执行length-1次上滤操作 for (int i = 1; i < list.length; i++) { PercolateUp(i); length++; for (int j = 1; j <= i; j++) { System.out.print(list[j] + " "); } System.out.println(); } } // 上滤——将要插入的元素放到最后位置 // 然后与其父结点比较,如果比父结点小,则将该结点与父节点交换 // 以此类推,直到找到最佳位置 private void PercolateUp(int i) { list[0] = list[i]; while (i > 0 && list[0] < list[i / 2]) { list[i] = list[i / 2]; i = i / 2; } list[i] = list[0]; } // 下滤 ——选择删除结点的两个孩子中的较小者放在删除结点的位置 // 到达叶子结点之后,将最后一个元素放到叶子结点 // 然后从该叶子结点进行上滤操作 private void PercolateDown() { System.out.print(list[1]+" "); int i = 1; while (true) { int lchild = i * 2; int rchild = i * 2 + 1; // 有两个孩子 if (rchild < length + 1 && (list[length] > list[lchild] || list[length] > list[rchild])) { if (list[lchild] < list[rchild]) { list[i] = list[lchild]; i = lchild; } else { list[i] = list[rchild]; i = rchild; } } else if (lchild < length + 1 && list[length] > list[lchild]) {// 只有左孩子 list[i] = list[lchild]; i = lchild; break; } else {// 叶节点,没有孩子 break; } } list[i] = list[length--]; } public void display() { System.out.println("排序:"); // 执行length-1次下滤操作 for (int i = 1; i < list.length; i++) { PercolateDown(); } System.out.println(); } public static void main(String[] args) { HeapSort heapsort = new HeapSort(); heapsort.display(); } }

运行结果:

297 35 658 170 208 821 810 732 904 884
建堆过程:
297
35 297
35 297 658
35 170 658 297
35 170 658 297 208
35 170 658 297 208 821
35 170 658 297 208 821 810
35 170 658 297 208 821 810 732
35 170 658 297 208 821 810 732 904
35 170 658 297 208 821 810 732 904 884
排序:
35 170 208 297 658 732 810 821 884 904

转载于:https://www.cnblogs.com/JPAORM/archive/2012/05/15/2510084.html

排序算法第六篇——堆排序相关推荐

  1. [ 数据结构 -- 手撕排序算法第四篇 ] 选择排序

    手撕排序算法系列之第四篇:选择排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括直接插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算 ...

  2. 八大排序算法总结——Java篇

    概述: 作为算法的鼻祖,八大排序是我们一定要了解学习的,废话不多说,直奔主题. 一. 直接插入排序 二.希尔排序 三.冒泡排序 四.快速排序 五.简单选择排序 六.堆排序 七.基数排序 八.归并排序 ...

  3. 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

    养成习惯,先赞后看!!! 你的点赞与关注真的对我非常有帮助.如果可以的话,动动手指,一键三连吧!!! 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 前言 这是十大经典排序算法详解的最后一篇了. ...

  4. [ 数据结构 -- 手撕排序算法第三篇 ] 希尔排序

    手撕排序算法系列之:希尔排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算法:排序算 ...

  5. 【排序算法】— 手写堆排序

    原创公众号:bigsai,码字不易,如有帮助,记得三联! 前言 在个人的专栏中,其他排序陆陆续续都已经写了,而堆排序迟迟没有写,在国庆假期的尾声,把堆排序也写一写. 插入类排序-(折半)插入排序.希尔 ...

  6. 经典排序算法(7)——堆排序算法详解

    堆排序(Heap sort)是指利用堆(最大堆.最小堆)这种数据结构所设计的一种排序算法.堆是一个完全二叉树的结构,并同时满足如下性质:即子结点的键值或索引总是小于(或者大于)它的父节点. 一.算法基 ...

  7. 堆排序时间复杂度_leetcode刷题(二):排序算法(归并排序,堆排序,桶排序)...

    今天,我们要来讲讲排序问题,这次讲的排序算法主要是归并排序,堆排序和桶排序. 归并排序 归并一词在中文的含义就是"合并,并入"的意思,在数据结构里面就是将两个或者两个以上的有序数组 ...

  8. 图解排序算法(基础篇)

    文章目录 一.冒泡排序 1.1 冒泡排序的第一种写法 1.2 冒泡排序的第二种写法 1.3 冒泡排序的第三种写法 二.选择排序 2.1 二元选择排序 三.插入排序 排序算法是一类非常经典的算法,说来简 ...

  9. 排序算法第四篇——冒泡排序

    算法描述: 依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个 ...

最新文章

  1. hadoop中MapReduce中压缩的使用及4种压缩格式的特征的比较
  2. ARP协议详解之ARP动态与静态条目的生命周期
  3. java使用jdbc的查询_如何在Java中使用多个查询使用JDBC
  4. 参数化查询为什么能够防止SQL注入
  5. python爬虫模块_python之爬虫_模块
  6. Netty工作笔记0046---异步模型原理剖析
  7. 爬虫+pyecharts数据分析实例:当当网
  8. 百面机器学习—3.逻辑回归与决策树要点总结
  9. ELK logstash gork匹配在线测试
  10. 《Word 排版艺术》一书的人到此交流
  11. 诺基亚:丑小鸭的重生
  12. 在北理珠,如何快速被动了解(社工)一个学生
  13. uniapp地图计算两点角度,旋转图标(轨迹回放)
  14. uwp浏览器java源码_uwp开发:webview模拟安卓浏览器
  15. 锐捷服务器虚拟化技术_交换机虚拟化技术.ppt
  16. Mask to Polygons mask转Polygons并展示
  17. window7(64bit)环境下安装基于TensorFlow后端的Keras 教程(CPU版)
  18. 实习第一天——网宿报到日
  19. Intellij IDEA2019版激活方式
  20. 关于Context的理解(转)

热门文章

  1. JS中的setInterval 函数体带参数f方法
  2. 垂涎欲滴!30个美味的食品类移动应用程序【下篇】
  3. [Java_kaikeba]java中堆和栈的区别(对象变量的理解)
  4. asp.net上传到服务器 步骤:
  5. 在C++中禁止或允许权限
  6. 校招刷题---java选择题笔记04
  7. null或空值的判断处理-java
  8. 量化策略回测01双均线
  9. 5mins看懂数据分析师必备的「波士顿模型」
  10. 银行有没有必要建立数据中台?看看这些架构师和技术总监怎么说