【数据结构】排序算法系列——堆排序(附源码+图解)

堆排序

堆排序基于一种常见的**[[二叉树]]结构**:

我们前面讲到选择排序,它在待排序的n个记录中选择一个最小的记录需要比较n一1次。本来这也可以理解,查找第一个数据需要比较这么多次是正常的,否则无法知道它是最小的记录。
可惜的是,这样的操作并没有把每一趟的比较结果保存下来,在后一趟的比较中,有许多比较在前一趟已经做过了,但由于前一趟排序时未保存这些比较结果,所以后一趟排序时又重复执行了这些比较操作,因而记录的比较次数较多。

那么我们有什么办法可以用来解决这样的重复比较的问题呢?

那么堆排序就由此而生了。简单来说,堆的性质包括如下几点:

堆(Heap)是一种特殊的树形数据结构,通常用作优先[[队列]]。堆排序算法利用了堆的性质来实现排序。堆的性质总结如下:

  1. 完全二叉树:堆是一种完全二叉树(Complete Binary Tree),即除了最后一层外,每一层的节点都是满的,且最后一层的节点从左到右依次排列。
  2. 堆的有序性
    • 大顶堆(Max-Heap):对于每一个节点 i,都满足 A[i] ≥ A[2i + 1]A[i] ≥ A[2i + 2](如果子节点存在)。即,父节点的值总是大于或等于其子节点的值。
    • 小顶堆(Min-Heap):对于每一个节点 i,都满足 A[i] ≤ A[2i + 1]A[i] ≤ A[2i + 2](如果子节点存在)。即,父节点的值总是小于或等于其子节点的值。
  3. 堆的高度:一个包含 n 个节点的堆的高度为 O(log n)。因为堆是完全二叉树,树的高度和节点数量的对数成正比。

根据堆的有序性和完全二叉树的性质,我们得知将其用在排序上是可行的,并且还能够有效减少重复比较的次数,这何乐而不为呢?

1964年,Floyd和Williams发明了堆这种数据结构,同时也发明了堆排序这种算法。

算法思想

鉴于堆的有序性,我们在进行堆排序时首先要构建一个大顶堆或者小顶堆,这里为了方便计算,我们统一为大顶堆。在大顶堆的性质下,可能会有人疑问:既然这个堆已经满足了有序性,那还需要排序什么呢?直接返回不就行了吗?其实不然。我们所知道的有序性的堆只是针对子节点与父节点之间的大小关系,例如以下堆:

在这里插入图片描述

我们可以看到,它确实满足大顶堆的性质:父节点永远大于子节点。但是当我们根据[[二叉树]]的遍历来进行输出时,会发现同一个父节点的子节点之间以及其中一个子节点的子节点实际上是无序的,例如60和10,它们之间是大于的关系;而60的子节点又都比10大,那么在遍历的时候,自然就不有序了。

所以堆实际上并不是完全有序的,而我们使用堆排序这个算法,也并非是根据这样的特征来进行的。我们直接看它的算法步骤:

  1. 首先建立大顶堆,然后将堆顶的元素取出,作为最大值,与数组尾部的元素交换,并维持残余堆的性质(也就是将剩余n-1个元素继续构成一个堆);
  2. 之后将堆顶的元素取出,作为次大值,与数组倒数第二位元素交换,并维持残余堆的性质;
  3. 以此类推,在第n-1次操作后,整个数组就完成了排序。

我们可以看到,实际上堆排序的核心思想就是将第一个根节点(最大值)与数组末尾的元素来进行交换(目的是为了构建无需新开辟空间就能直接构建有序数组,末尾元素被交换后也不会影响大顶堆的重新构建),然后重新构造堆,那么此时的第二个根节点就仅次于第一个根节点的大小,这么以此类推,最终将所有节点根据大、次大、第三大的顺序排序在数组中,那么也就成功构建出了有序的数组。

C语言代码分析

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);}*/for (int i = (n - 1 - 1) / 2; i >= 0; i++)//从最后一个非叶子节点开始调整{AdjustDown(a, n, i);}int end = n-1;while (end > 0)//每次将堆顶元素与最后一个元素交换,然后调整堆{Swap(&a[end], &a[0]);AdjustDown(a, end, 0);end--;}
}

时间复杂度

我们发现堆的算法实际上是基于[[二叉树]]排序的,并且在最坏情况和最好情况下的堆排序都是同一量级的操作,所以我们得出其时间复杂度为:O(n logn)

稳定性

鉴于堆排序会改变前后元素的相对位置,所以:不稳定

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

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

相关文章

BCLinux您的授权码是无效的,请获得正确的授权码来注册大云Linux操作系统

更新yum源老弹出这个&#xff0c;很烦人。 [rootlocalhost yum.repos.d]# yum clean all 服务器检查结果: ***信息***您的授权码是无效的&#xff0c;请获得正确的授权码来注册大云Linux操作系统。您可以使用bclinux-license -g命令获得机器码&#xff0c;然后与我们联系帮您产…

网络安全:建筑公司会计软件遭受暴力攻击

黑客正在暴力破解基金会会计服务器上高权限账户的密码&#xff0c;这些账户广泛用于建筑行业&#xff0c;从而侵入企业网络。 这一恶意活动最先被 Huntress 发现&#xff0c;其研究人员于 2024 年 9 月 14 日检测到了此次攻击。 Huntress 已经发现这些攻击对管道、暖通空调、…

ChatGPT提示词-中文版(awesome-chatgpt-prompts中文版)

原是Github上110.6K星的项目&#xff1a;GitHub - f/awesome-chatgpt-prompts: This repo includes ChatGPT prompt curation to use ChatGPT better. 我翻译成了中文需要自提 我用夸克网盘分享了「Chat GPT提示词.csv」&#xff0c;点击链接即可保存。打开「夸克APP」在线查看…

考研数学精解【3】

文章目录 重要公式定理运算公式大全 重要公式定理 运算公式大全

VirtualBox7.1.0 安装 Ubuntu22.04.5 虚拟机

环境 &#xff08;1&#xff09;宿主机系统&#xff1a;Windows10 &#xff08;2&#xff09;虚拟机软件&#xff1a;VirtualBox7.1.0 &#xff08;3&#xff09;虚拟机系统&#xff1a;Ubuntu 22.04.5 LTS (Jammy Jellyfish) 安装虚拟机 &#xff08;1&#xff09;第一步…

MyBatis中一对多关系的两种处理方法

目录 1.多表联查&#xff08;通过collection标签的ofType属性&#xff09; 1&#xff09;mapper 2&#xff09;mapper.xml 3&#xff09;测试代码 4&#xff09;测试结果 2.分布查询(通过collection标签的select属性) 1&#xff09;mapper 2&#xff09;mapper.xml 3&#xff0…

【机器学习】--- 生成对抗网络 (GANs)

生成对抗网络 (GANs) —— 机器学习中的一个热点 生成对抗网络&#xff08;GANs, Generative Adversarial Networks&#xff09;近年来在机器学习领域成为一个热点话题。自从Ian Goodfellow及其团队在2014年提出这一模型架构以来&#xff0c;GANs 在图像生成、数据增强、风格转…

Android开发高频面试题之——Android篇

Android开发高频面试题之——Android篇 Android开发高频面试题之——Java基础篇 Android开发高频面试题之——Kotlin基础篇 Android开发高频面试题之——Android基础篇 1. Activity启动模式 standard 标准模式,每次都是新建Activity实例。singleTop 栈顶复用。如果要启动的A…

使用Docker安装 Skywalking(单机版)

使用Docker安装 Skywalking&#xff08;单机版&#xff09; 文章目录 使用Docker安装 Skywalking&#xff08;单机版&#xff09;Skywalking 介绍Skywalking 安装 Skywalking 介绍 Skywalking官网 分布式系统的应用程序性能监视工具&#xff0c;专为微服务、云原生架构和基于容…

水果成熟度检测系统源码分享

水果成熟度检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

如何准备教师资格证科目三“学科知识与教学能力”的考试与面试?(理科导向:数学/物理)

如何准备教师资格证科目三“学科知识与教学能力”的考试与面试&#xff1f;&#xff08;理科导向&#xff1a;数学/物理&#xff09; ​ 目录 收起 1 前言 1.1 自身经历 1.2 教师资格证的作用 2 知识点题型分数的分布与学习建议 2.1 科目三的知识点分数分布&#xff1a; …

提高数据集成稳定性:EMQX Platform 端到端规则调试指南

自 5.7.0 版本起&#xff0c;EMQX 支持了 SQL 调试&#xff0c;并支持在数据集成全流程中进行规则调试&#xff0c;使用户能够在开发阶段就全面验证和优化规则&#xff0c;确保它们在生产环境中的稳定高效运行。 点击此处下载 EMQX 最新版本&#xff1a;https://www.emqx.com/z…

【C++语言】C/C++内存管理

一、C/C内存分布 我们先来看一看C/C中有哪些区域&#xff0c;为什么C/C中区分这些区域呢&#xff1f;&#xff1f;不同的数据有不同的存储需求&#xff0c;各个区域满足不同的需求。我们有临时用的数据&#xff0c;该数据是存储在栈帧区域的&#xff1b;在一些数据结构中&#…

自媒体起号新思路!利用AI创作治愈类内容的运营指南

最近&#xff0c;治愈类内容在各大社交平台上备受欢迎。无论是刷短视频还是看小红书&#xff0c;都能发现这类账号的流量巨大&#xff0c;粉丝数量飞速增长。 总而言之&#xff0c;汇成一句话&#xff1a; 如何利用AI技术&#xff0c;创作治愈类的图片和视频&#xff0c;吸引粉…

JavaEE:网络初识

文章目录 网络初识网络中的重要概念IP地址端口号认识协议(最核心概念)OSI七层模型TCP/IP五层(或四层)网络模型网络设备所在分层封装和分用 网络初识 网络中的重要概念 网络互联的目的是进行网络通信,也是网络数据传输,更具体一点,是网络主机中的不同进程间,基于网络传输数据.…

html,css基础知识点笔记(二)

9.18&#xff08;二&#xff09; 本文主要教列表的样式设计 1&#xff09;文本溢出 效果图 文字限制一行显示几个字&#xff0c;多余打点 line-height: 1.8em; white-space: nowrap; width: 40em; overflow: hidden; text-overflow: ellipsis;em表示一个文字的大小单位&…

计算机人工智能前沿进展-大语言模型方向-2024-09-18

计算机人工智能前沿进展-大语言模型方向-2024-09-18 1. The Application of Large Language Models in Primary Healthcare Services and the Challenges W YAN, J HU, H ZENG, M LIU, W LIANG - Chinese General Practice, 2024 人工智能大语言模型在基层医疗卫生服务中的应…

【Delphi】知道控件名称(字符串),访问控件

在 Delphi 中&#xff0c;可以使用 RTTI&#xff08;运行时类型信息&#xff09; 或其他方法通过对象的名称字符串来访问对象。比如&#xff0c;如果你有一个控件的名称字符串&#xff0c;你希望通过该名称找到并访问实际的控件。 以下是通过 RTTI 以及其他技术&#xff08;如…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》&#xff0c;在设置完自定义字段后&#xff0c;如下图&#xff0c;通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复&#xff0c;若是客户常用的定义字段&#xff0c;也可以把这些用户…

图片类型转化---模拟某wps

文件上传功能的深入探讨 文件上传是Web应用程序中常见的功能&#xff0c;它允许用户将本地文件通过Web界面发送到服务器。在Flask中&#xff0c;这通常是通过处理表单数据来实现的。表单必须设置enctype为multipart/form-data&#xff0c;这样浏览器才能将文件作为多部分消息发…