堆排序的时间复杂度O(N*logN),额外空间复杂度O(1),是一个不稳定性的排序

目录

一 准备知识

1.1  大根堆和小根堆

二 堆排序基本步骤

2.1 构造堆

2.2 固定最大值再构造堆

三 总结

四 代码


一 准备知识

堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆

1.1  大根堆和小根堆

性质:每个结点的值都大于其左孩子和右孩子结点的值,称之为大根堆;每个结点的值都小于其左孩子和右孩子结点的值,称之为小根堆。如下图

我们对上面的图中每个数都进行了标记,上面的结构映射成数组就变成了下面这个样子

还有一个基本概念:查找数组中某个数的父结点和左右孩子结点,比如已知索引为i的数,那么

1.父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)

2.左孩子索引:2*i+1

3.右孩子索引:2*i+2

所以上面两个数组可以脑补成堆结构,因为他们满足堆的定义性质:

大根堆:arr(i)>arr(2*i+1) && arr(i)>arr(2*i+2)

小根堆:arr(i)<arr(2*i+1) && arr(i)<arr(2*i+2)

二 堆排序基本步骤

基本思想:

1.首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端

2.将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1

3.将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

2.1 构造堆

将无序数组构造成一个大根堆(升序用大根堆,降序就用小根堆)

假设存在以下数组

主要思路:第一次保证0~0位置大根堆结构(废话),第二次保证0~1位置大根堆结构,第三次保证0~2位置大根堆结构...直到保证0~n-1位置大根堆结构(每次新插入的数据都与其父结点进行比较,如果插入的数比父结点大,则与父结点交换,否则一直向上交换,直到小于等于父结点,或者来到了顶端)

插入6的时候,6大于他的父结点3,即arr(1)>arr(0),则交换;此时,保证了0~1位置是大根堆结构,如下图:

(友情提示:待交换的数为蓝色,交换后的数为绿色)

插入8的时候,8大于其父结点6,即arr(2)>arr(0),则交换;此时,保证了0~2位置是大根堆结构,如下图

插入5的时候,5大于其父结点3,则交换,交换之后,5又发现比8小,所以不交换;此时,保证了0~3位置大根堆结构,如下图

插入7的时候,7大于其父结点5,则交换,交换之后,7又发现比8小,所以不交换;此时整个数组已经是大根堆结构

2.2 固定最大值再构造堆

此时,我们已经得到一个大根堆,下面将顶端的数与最后一位数交换,然后将剩余的数再构造成一个大根堆

(友情提示:黑色的为固定好的数字,不再参与排序)

此时最大数8已经来到末尾,则固定不动,后面只需要对顶端的数据进行操作即可,拿顶端的数与其左右孩子较大的数进行比较,如果顶端的数大于其左右孩子较大的数,则停止,如果顶端的数小于其左右孩子较大的数,则交换,然后继续与下面的孩子进行比较

下图中,5的左右孩子中,左孩子7比右孩子6大,则5与7进行比较,发现5<7,则交换;交换后,发现5已经大于他的左孩子,说明剩余的数已经构成大根堆,后面就是重复固定最大值,然后构造大根堆

如下图:顶端数7与末尾数3进行交换,固定好7,

剩余的数开始构造大根堆 ,然后顶端数与末尾数交换,固定最大值再构造大根堆,重复执行上面的操作,最终会得到有序数组

三 总结

到这里,大家应该对堆排序都有了自己的见解,我们对上面的流程总结下:

1、首先将无需数组构造成一个大根堆(新插入的数据与其父结点比较)

2、固定一个最大值,将剩余的数重新构造成一个大根堆,重复这样的过程

四 代码

代码中主要两个方法:

1、将待排序数组构造成一个大根堆(元素上升)

2、固定一个最大值,将剩余的数再构造成一个大根堆(元素下降)

    //堆排序public static void heapSort(int[] arr) {//构造大根堆heapInsert(arr);int size = arr.length;while (size > 1) {//固定最大值swap(arr, 0, size - 1);size--;//构造大根堆heapify(arr, 0, size);}}//构造大根堆(通过新插入的数上升)public static void heapInsert(int[] arr) {for (int i = 0; i < arr.length; i++) {//当前插入的索引int currentIndex = i;//父结点索引int fatherIndex = (currentIndex - 1) / 2;//如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点//然后继续和上面的父结点值比较,直到不大于父结点,则退出循环while (arr[currentIndex] > arr[fatherIndex]) {//交换当前结点与父结点的值swap(arr, currentIndex, fatherIndex);//将当前索引指向父索引currentIndex = fatherIndex;//重新计算当前索引的父索引fatherIndex = (currentIndex - 1) / 2;}}}//将剩余的数构造成大根堆(通过顶端的数下降)public static void heapify(int[] arr, int index, int size) {int left = 2 * index + 1;int right = 2 * index + 2;while (left < size) {int largestIndex;//判断孩子中较大的值的索引(要确保右孩子在size范围之内)if (arr[left] < arr[right] && right < size) {largestIndex = right;} else {largestIndex = left;}//比较父结点的值与孩子中较大的值,并确定最大值的索引if (arr[index] > arr[largestIndex]) {largestIndex = index;}//如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环if (index == largestIndex) {break;}//父结点不是最大值,与孩子中较大的值交换swap(arr, largestIndex, index);//将索引指向孩子中较大的值的索引index = largestIndex;//重新计算交换之后的孩子的索引left = 2 * index + 1;right = 2 * index + 2;}}//交换数组中两个元素的值public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}

转载:https://guguoyu.blog.csdn.net/article/details/81283998

【转载】堆排序算法(图解详细流程)相关推荐

  1. 堆排序算法原理及C++实现(详细注释)

    1.算法原理 原理部分参考下面这个博客即可: 堆排序算法(图解详细流程) 2.C++实现: 解法一:利用vector实现最大堆 注意:heap_max这个函数调用了两次: 建堆时候和交换最大值之后分别 ...

  2. 【路径规划】Dijkstra算法——超详细原理图解

    Dijkstra算法详解 1. Dijkstra算法原理  1.1. 有向图的Dijkstra算法  1.2. 无向图和栅格网络的拓展   1.2.1. 无向图   1.2.2. 栅格网络 2. Di ...

  3. 上标3下标6算法_图解堆排序算法

    堆排序定义 一般来说,算法就像数学公式,前人经过不断优化和验证得到有规律性的公式留给后人使用,当然也会交给后人验证的思路.那么堆排序算法就是这样,它有基本固定的定义如下: 1.将数组构建为一颗有规则的 ...

  4. 史上最详细:YOLO v3算法的具体流程和实现细节

    本文是我对YOLO算法的细节理解总结,本文的阅读前提是已读过YOLO相关论文,文中不会谈及YOLO的发展过程,不会与其他对象检测算法进行对比,也不会介绍YOLO9000相关的内容,只总结YOLOv3算 ...

  5. 十大经典排序算法----堆排序(超详细)

    目录 1. 堆排序的基础知识 1.1 大顶堆&&小顶堆 1.2 向下调整算法 1.3 物理结构与逻辑结构的关系 2. 堆排序详解 2.1 堆排序整体思路 2.2 思路详解 2.2.1  ...

  6. SORT跟踪算法的详细解释,不容错过

    转载自:https://blog.csdn.net/HaoBBNuanMM/article/details/85555547 SORT - SIMPLE ONLINE AND REALTIME TRA ...

  7. 精通八大排序算法系列:二、堆排序算法

    精通八大排序算法系列:二.堆排序算法 作者:July .二零一一年二月二十日 本文参考:Introduction To Algorithms,second edition. ------------- ...

  8. 算法图解:如何用两个栈实现一个队列?

    作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 本文已收录至 https://github.com/vipstone/algori ...

  9. 算法图解:如何判断括号是否有效?

    作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 今天要讲的这道题是 bilibili 今年的笔试真题,也是一道关于栈的经典面试题. ...

  10. 堆排序算法原理及c++实现

    文章目录 准备知识 MAX-HEAPIFY过程 建堆 堆排序算法 总结 准备知识 堆的结构可以分为最大堆和最小堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序. 所谓完全二叉树即叶节 ...

最新文章

  1. 如何站在使用者的角度来设计SDK-微信公众号开发SDK(消息处理)设计之抛砖引玉...
  2. 学习SpringMVC——从HelloWorld开始
  3. ai人工智能python开发_Python才是人工智能AI的首选编程语言,你值得拥有……
  4. 大二c语言期末考试题库及详解答案,大学C语言期末考试练习题(带详解答案)...
  5. 互联网日报 | 7月31日 星期六 | 小米手机销量晋升全球第二;苏宁易购上半年亏损31.9亿元;亚马逊被欧盟罚款8.88亿美元...
  6. numpy实用技巧(二)
  7. openssl做HMAC实例(C++)
  8. 如何在 macOS Monterey 中更改光标颜色
  9. SqlDataReader 之指定转换无效
  10. python教师管理系统,Python面向对象实战:学生教师信息管理(3)
  11. Apollo无人驾驶系统基础入门(云服务+感知(一))
  12. 思科路由器配置命令(四)
  13. Java面试智力题逻辑题汇总2021
  14. python爬虫之如何建立一个自己的代理IP池
  15. 腾讯全套人力资源管理资料大全(职位能力模型图+人力资源管理+招聘体系+培训体系+薪酬绩效+员工职业发展,共174M)
  16. Xilinx XC7Z020双核ARM+FPGA开发板试用
  17. 达叔926词汇pdf单词提取、保存
  18. intellij IDEA 中,.properties文件unicode转中文
  19. mq5 EA模板及双均线交叉策略EAdemo
  20. PySide2安装教程

热门文章

  1. 查看oracle磁盘组空间,shell脚本检查oracle中的ASM磁盘组空间并发送邮件
  2. 分享一个xshell7的绿色版
  3. PHP利用JWT实现token和refresh_token
  4. 鸟哥私房菜重温笔记4
  5. arccatalog点要素显示不完_改变人际关系核心要素,不讨好不献媚,牢记这3点,受益一生...
  6. acwing-提高课
  7. 惩罚函数将有约束优化转化为无约束优化问题
  8. 信息流广告投放分析实战案例!
  9. IAST 实践利用洞态做开源组件的安全治理
  10. 核方法(kernel Method)