【数据结构】堆排序详解

文章目录

  • 一、堆排序思想
  • 二、向上调整建堆排序
  • 三、向下调整建堆排序
  • 四、总结

对于什么是堆,堆的概念分类以及堆的向上和向下两种调整算法可见: 堆的创建

在这里插入图片描述

一、堆排序思想

int a[] = { 2,3,5,7,4,6 };

对于这样一个数组来说,要想要用堆排序对它进行排序,首先要做的就是用数组里的数据建立一个堆,大堆和小堆都可以,只有是一个堆才能使用堆排序。

那么应该建大堆还是小堆呢,例如对于这个数组要排升序,如果建立小堆的话
在这里插入图片描述

建成小堆后找出了最小的元素,要找到次小的就需要把剩下的元素看作堆,但剩下的元素不一定是堆,需要重新建堆,代价比较大。

更好的方法是升序建立大堆,堆顶和最后一个元素交换,最后一个最大的元素就已经有序,对剩下数据进行向下调整,就能找出第二大的,以此就能将数组排好序。

总结一下堆排序的思想就是:
1、根据要排什么序建大堆或小堆,此时堆顶端的元素就是最值
2、将顶端元素和末尾元素交换,此时末尾元素就是有序的,剩下的还有n-1个元素
3、将剩下的n-1个元素再次构建成堆,然后将堆顶端元素与第n-1个元素互换,反复执行便可得到有序数组

升序:建大堆
降序:建小堆

二、向上调整建堆排序

使用向上调整算法建堆的堆排序

例如:将数组a用堆排序按从小到大排列(升序)

在这里插入图片描述
首先,利用向上调整算法建大堆,此方法可参考堆的创建

向上调整算法的前提条件是:前面的元素是堆

对于单个结点来说既可以看作一个大堆,所以便可以通过向上调整算法依次对数组元素进行调整,那进行调整的元素前就一定是堆,满足条件

在这里插入图片描述

创建好的大堆如下:
在这里插入图片描述

将堆的顶端元素7和末尾元素2进行交换,对除7外剩下的元素进行向下调整重新构建大堆
在这里插入图片描述
此时7已经是有序的,将元素6和元素3进行交换,对除6、7外剩下元素进行向下调整重新构建大堆
在这里插入图片描述
此时6、7已经有序,将元素5和元素2进行交换,对除5、6、7外剩下元素进行向下调整重新构建大堆
在这里插入图片描述
此时5、6、7已经有序,将元素4和元素2进行交换,此时数组已经有序在这里插入图片描述
排序完数组a变为
在这里插入图片描述

向上调整算法建堆升序的堆排序代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
//交换结点的函数
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//向上调整算法(大堆)
void AdjustUp(HPDataType* a, int child)
{//找出双亲的下标int parent = (child - 1) / 2;while (child>0){//孩子结点比双亲大则交换if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}//向下调整算法(大堆)
void AdjustDown(HPDataType* a, int n, int parent)
{//先默认左孩子是较大的int child = parent * 2 + 1;while (child < n){//找出左右孩子中较大的if (child + 1 < n && a[child + 1] > a[child]){child++;}//孩子节点更小则交换if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
//排序
void HeapSort(int* a, int n)
{//向上调整建堆for (int i = 1; i < n; i++){AdjustUp(a, i);}//最尾端数据下标为总数减一int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);//对剩余元素进行向下调整AdjustDown(a, end, 0);end--;}
}
int main()
{int a[] = { 2,3,5,7,4,6 };HeapSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

运行结果如下:
在这里插入图片描述

空间复杂度:O(1)
平均时间复杂度:O(nlogn)

三、向下调整建堆排序

向下调整建堆排序与向上调整建堆排序不同的地方就在于建堆时用的算法不同,建好堆之后的后续操作都是相同的。

还是对上面那个案例,我们用向下调整算法建堆
在这里插入图片描述

向下调整算法前提条件:左右子树必须是堆,才能调整

在这里插入图片描述

对于这个完全二叉树来说,它的倒数第一个非叶子节点2的左子树为4,没有右子树,可以用向下调整,再上一个节点6的左右子树是单个节点也可以看作堆,所有我们就可以从倒数第一个非叶子节点也就是最后一个节点的父亲开始向下调整:

在这里插入图片描述

利用向下调整建好堆之后的后续操作与向上调整建好堆之后的操作一样,这里就不再演示

向下调整算法建堆升序的堆排序代码更改如下:

void HeapSort(int* a, int n)
{向上调整建堆//for (int i = 1; i < n; i++)//{//	AdjustUp(a, i);//}// //向下调整建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}//最尾端数据下标为总数减一int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);//对剩余元素进行向下调整AdjustDown(a, end, 0);end--;}
}

利用向下调整建堆的堆排序时间复杂度为:O(n),比利用向上调整建堆更优

四、总结

使用堆排序需要先建堆,建堆有向上调整算法和向下调整算法两种方法,但向下调整算法的平均时间复杂度更低,建好堆之后便首尾数据互换,再对剩下元素重新建堆,反复执行便可得到有序数列。

重点知识总结:

  • 小堆:所有的双亲结点都小于孩子节点,根节点最小
  • 大堆:所有的双亲结点都大于孩子节点,根节点最大
  • 向下调整算法前提:左右子树必须是堆,才能调整
  • 向上调整算法前提:前面的元素是堆
  • 堆排序建堆时:升序建大堆,降序建小堆

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/79903.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ...

项目开发遇到下面这个报错了&#xff01; 问题原因 直接说原因&#xff0c;就是因为进程间不能直接传递对象&#xff0c;应该传递该Binder对象的映射&#xff08;代理对象&#xff09;&#xff0c;所以类型转换就出错了。如果在同一个进程中&#xff0c;直接传递对象没有关系&a…

9月15日作业

Qt代码 #include "mywnd.h"//构造函数的定义 mywnd::mywnd(QWidget *parent): QWidget(parent) //显性调用父类的有参构造完成对子类从父类继承下来成员的初始化工作 {//窗口设置this->resize(QSize(500, 433));this->setWindowTitle("Widget&quo…

安装GPU驱动,CUDA Toolkit和配置与CUDA对应的Pytorch

如果有帮助,记得回来点个赞 目录 1.安装指定GPU驱动如果安装的GPU CUDA Version和CUDA Toolkit版本已经冲突怎么办? 2.安装指定版本的CUDA Toolkit如果我安装了CUDA Toolkit之后nvcc -V仍然显示旧的CUDA Toolkit版本怎么办? 3.安装与CUDA对应的Pytorch已经安装了错乱版本的c…

《C++ primer plus》精炼(OOP部分)——对象和类(4)

“学习是人类进步的阶梯&#xff0c;也是个人成功的基石。” - 罗伯特肯尼迪 文章目录 友元函数利用友元函数重载<<运算符重载部分示例&#xff1a;矢量类 友元函数 先看看在上一章中我们作为例子的代码&#xff1a; class Student{string name;int grade;int operator…

第十九章、【Linux】开机流程、模块管理与Loader

19.1.1 开机流程一览 以个人计算机架设的 Linux 主机为例&#xff0c;当你按下电源按键后计算机硬件会主动的读取 BIOS 或 UEFI BIOS 来载入硬件信息及进行硬件系统的自我测试&#xff0c; 之后系统会主动的去读取第一个可开机的设备 &#xff08;由 BIOS 设置的&#xff09; …

如何实现wingftpserver部署到外网访问?快解析p2p内网穿透

不少朋友选择用wing FTP来搭建部署FTP服务管理文件共享。Wing FTP Server是一个跨平台ftp服务器端&#xff0c;它有不错的可靠性和一个友好的配置界面&#xff0c;Wing FTP Server除了能提供FTP的基本服务功能以外&#xff0c;还能提供管理员终端、任务计划、基于Web的管理端和…

中国智能客服发展历程

中国智能客服的发展历程&#xff1a; 在2000年以前&#xff0c;互联网尚未普及&#xff0c;客服主要以电话沟通为主。从2000年到2010年&#xff0c;得益于计算机技术、计算机电话集成技术&#xff08;CTI&#xff09;、网络技术、多媒体机技术以及CRM、BI、ERP、OA等企业信息化…

基于SSM+Vue的校园教务系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

MATLAB入门-字符串操作

MATLAB入门-字符串操作 注&#xff1a;本篇文章是学习笔记&#xff0c;课程链接是&#xff1a;link MATLAB中的字符串特性&#xff1a; 无论是字符还是字符串&#xff0c;都要使用单引号来‘’表示&#xff1b;在MATLAB中&#xff0c;字符都是在矩阵中存储的&#xff0c;无论…

Leetcode: 645.错误的集合 题解【超详细】

题目 集合 s 包含从 1 到 n 的整数。不幸的是&#xff0c;因为数据错误&#xff0c;导致集合里面某一个数字复制了成了集合里面的另外一个数字的值&#xff0c;导致集合 丢失了一个数字 并且 有一个数字重复 。 给定一个数组 nums 代表了集合 S 发生错误后的结果。 请你找出重复…

新手如何开始Microstation CE版二次开发

一步步学习MicroStation CE MDL&#xff08;C&#xff09;开发 - 技术资料库 - Bentley 中国优先社区 - Bentley Communities https://communities.bentley.com/communities/other_communities/chinafirst/w/chinawiki/57704/microstation-ce-mdl-c一步步学习MicroStation CE A…

算法:合并两个有序数组---双指针[1]

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132673462 欢迎各位大佬指点、三连 1、题目&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元…

小节5:Python列表list常用操作

1、对列表的基本认知&#xff1a; 列表list&#xff0c;是可变类型。比如&#xff0c;append()函数会直接改变列表本身&#xff0c;往列表里卖弄添加元素。所以&#xff0c;list_a list_a.append(123)就是错误的。如果想删除列表中的元素&#xff0c;可以用remove()函数&…

Android RecyclerView BaseSectionQuickAdapter实现分组功能

详情网站&#xff1a;手把手教你使用BaseSectionQuickAdapter实现分组功能&#xff0c;史上最详细Adapter使用教程_basequickadapter 分组_杨阿程的博客-CSDN博客 //加入二个包implementation com.android.support:recyclerview-v7:26.0.0-beta1implementation com.github.Cym…

2023/9/15 -- C++/QT

作业&#xff1a; 1> 将工程文件进行注释 2> 03login_box.pro: QT core gui #core核心库 gui图形开发库greaterThan(QT_MAJOR_VERSION, 4): QT widgets #4.0版本以上自动包含widgets库CONFIG c11 #支持C11版本# The following define makes your compiler em…

深度学习推荐系统(八)AFM模型及其在Criteo数据集上的应用

深度学习推荐系统(八)AFM模型及其在Criteo数据集上的应用 1 AFM模型原理及其实现 沿着特征工程自动化的思路&#xff0c;深度学习模型从 PNN ⼀路⾛来&#xff0c;经过了Wide&#xff06;Deep、Deep&#xff06;Cross、FNN、DeepFM、NFM等模型&#xff0c;进⾏了大量的、基于不…

idea装载jerbel以及文件上传下载

一、JRebel 1.1 Jrebel介绍 JRebel是一个Java开发工具&#xff0c;它是一款用于实时代码重载的插件。它的主要功能是在不重新启动应用程序的情况下&#xff0c;将修改后的Java代码实时应用到正在运行的应用程序中&#xff0c;从而加快开发周期&#xff0c;提高开发效率。 实…

Sqlserver如何调试存储过程

前提&#xff1a;需要使用Sql Server Managerment Studio 工具进行调试。 步骤&#xff1a; 1.选择存储过程&#xff0c;右键选择“执行存储过程”。操作过后&#xff0c;会生成一个调用存储过程的代码块。 2.以编辑模式打开所以需要调试的存储过程。 3.点击调试按钮进行调…

【视觉检测】电源线圈上的导线弯直与否视觉检测系统软硬件方案

 检测内容 线圈上的导线弯直与否检测系统。  检测要求 检测线圈上的导线有无弯曲&#xff0c;弯曲度由客户自己设定。检测速度5K/8H625PCS/H。  视觉可行性分析 对样品进行了光学实验&#xff0c;并进行图像处理&#xff0c;原则上可以使用机器视觉进行测试测量…

数据结构与算法--排序算法复习

目录 1.三种常见的简单排序&#xff1a; 1.1冒泡排序 1.2 选择排序 1.3 插⼊排序 2 常见高级排序算法 2.1 希尔排序 2.2 快速排序 2.3 归并排序 2.4计数排序 先上结论&#xff1a; 1.三种常见的简单排序&#xff1a; 1.1冒泡排序 1.⾸先在未排序数组的⾸位开始&#…