十大排序算法之堆排序

堆排序

在简单选择排序文章中,简单选择排序这个“铁憨憨”只顾着自己做比较,并没有将对比较结果进行保存,因此只能一遍遍地重复相同的比较操作,降低了效率。针对这样的操作,Robertw.Floyd 在1964年提出了简单选择排序的升级版——堆排序方法。
堆是什么呢?堆是用数组实现的已标号的完全二叉树。

1. 算法思想

在讲算法思想前,先解释几个基本知识点。就像上文所说的:用数组实现的已标号的完全二双树称之为堆。如果父节点的键值均不小于子节点,则为大顶堆;如果父节点的键值均不大于子节点,则为小顶堆,如下图所示。
在这里插入图片描述
圆圈旁边的数字即为节点的索引,如果我们按照这个索引将节点的逻辑结构映射到数组中,就变成了如下图所示的存储结构。
在这里插入图片描述

我们再用两个公式简单地描述一下节点之间的关系。
大顶堆: a r r [ i ] ≥ a r r [ 2 i + 1 ] arr[i] \geq arr[2i+1] arr[i]arr[2i+1] && a r r [ i ] ≤ a r r [ 2 i + 2 ] arr[i] \leq arr[2i+2] arr[i]arr[2i+2]
小顶堆: a r r [ i ] ≤ a r r [ 2 i + 1 ] arr[i] \leq arr[2i+1] arr[i]arr[2i+1] && a r r [ i ] ≥ a r r [ 2 i + 2 ] arr[i] \geq arr[2i+2] arr[i]arr[2i+2]
如果大家看懂了这两个公式,那么就会理解堆排序的基本思想:一次又一次地将待排序数组构造成一个大顶堆,然后一次又一次地将大顶堆的根节点(最大值)和最末尾的元素交换位置并将最末尾的元素隔离,直到整个序列变得有序。

2. 算法步骤

假设初始序列的堆结构如下图所示。
在这里插入图片描述

(1)将待排序数组构建成一个大顶堆(若降序排列,则采用小顶堆)。
为了构建大顶堆,我们需要从最后一个非叶子节点开始先从左到右,再从上到下地进行调整。最后一个非叶子节点的计算公式为:
a r r . l e n g t h 2 − 1 = 6 2 − 1 = 2 \frac{arr.length}{2}-1=\frac{6}{2}-1=2 2arr.length1=261=2
即为“2”节点,由于8>2,所以将二者交换,如下图所示。
在这里插入图片描述
找到第二个非叶子节点“5”,因为[5,1,3]中5最大,所以无须进行交换。第三个非叶子节点为“1”,因为[1,5,8]中8最大,所以1和8交换,如下图所示。
在这里插入图片描述我们发现,这次交换后右子树又被打乱了,2比1大,因此需要再更新一下,如下图所示。
在这里插入图片描述

这样,我们成功地将待排序数组构建成第一个大顶堆。
在这里插入图片描述
(3)重复步骤(1)和(2),直到整个序列变得有序。
重新调整数组结构,使其满足大顶堆的结构,如下图所示。
在这里插入图片描述
然后继续交换堆顶和堆底的元素,又“沉”了一个,如下图所示。
在这里插入图片描述
接下来都是类似操作,就这样一直执行,直到整个数组变得有序,如下图所示。
在这里插入图片描述

3. 算法分析

有的读者肯定有疑问,为什么在经过步骤(1)和步骤(2),进行了四五次比较和交换的操作后,得到的有序数组意然和开始的待排序数组是一样的,都是[1,5,2,1,3,8]呢?其实这也是堆排序的一个不足之处。那么我们如何最大化地提升堆排序的效率呢?这个问题就交给大家去思考吧。
堆排序的思想总结起来有两点:构建堆结构+交换堆顶和堆底元素。构建第一个大顶堆时,时间复杂度为O(n)之后还有n-1次的交换元素和交换之后堆的重建,根据完全二叉树的性质来说,操作次数应该是呈 l o g ( n − 1 ) , l o g ( n − 2 ) , l o g ( n − 3 ) , ⋯ , 1 log(n-1),log(n-2),log(n-3),\cdots,1 log(n1),log(n2),log(n3),,1的态势逐步递减的,也就近似为 O ( l o g 2 n ) O(log_2 n) O(log2n)。因此,不难得出,堆排序的时间复杂度为 O ( n l o g n ) O(nlog {\ }n) O(nlog n)
同样,当待排序数组是逆序时,就是最坏的情况。这时候不仅需要进行 O ( n l o g n ) O(nlog {\ }n) O(nlog n)复杂度的比较操作,还需要进行 O ( n l o g n ) O(nlog {\ }n) O(nlog n)复杂度的交顿操作,加起来总的时间复杂度为 O ( n l o g n ) O(nlog {\ }n) O(nlog n)
最好的情况则是正序的时候,只需要进行 O ( n l o g n ) O(nlog {\ }n) O(nlog n)复杂度的比较操作,而不需移动操作,不过总的时间复杂度还是 O ( n l o g n ) O(nlog {\ }n) O(nlog n)。也就是说,待排序数据的原始分布情况对堆排序的效率影响是比较小的。
另外,堆排序也是不稳定排序。

4. 算法代码

算法代码如下:
Pyhton

#堆排序
def heap_sort(array) :"""这里需要注意两点:(1)递归思想(2)列表切片"""length = len(array)#当数组 array 的长度为1时,说明只有一个元素if length<= 1:#无须排序,直接返回原列表return array# 若存在两个或以上节点else:#调整成大顶堆:按照先从下往上,再从左到右的顺序进行调整# 从最后一个非叶子节点(length//2-1)开始向前遍历,直到根节点for i in range(length//2-1,-1,-1):# //为取整# 当左孩儿大于父节点时if array[2*i+1] > array[i]:#二者交換位置array[2*i+1],array[i]=array[i],array[2*i+1] # 如果右孩儿存在且大于父节点时if 2*i+2 <= length-1:if array[2*i+2]> array[i]:#二者交換位置array[2*i+2],array[i] = array[i], array[2*i+2]'''此处省略重构建过程,对结果并不影响!'''# 将堆顶元素与末尾元素进行交换,使最大元素“沉”到数组末尾array[0],array[length-1] = array[length-1], array[0]#递归调用 heap_sort函数对前n-1个元素进行堆排序并返回排序后的结果return heap_sort(array [0:length-1]) + array[length-1:]
# 调用 heapsort 函数
print(heap_sort([34, 21, 13, 2, 5, 1, 55, 3, 1, 8]))

Java

    public static int[] heap_sort(int[] array) {int length = array.length;if (length <= 1) {return array;} else {// 构建最大堆for (int i = length / 2 - 1; i >= 0; i--) {maxHeapify(array, i, length);}// 交换堆顶元素与末尾元素并减小堆大小for (int end = length - 1; end > 0; end--) {swap(array, 0, end);length--;maxHeapify(array, 0, length); // 调整堆}}return array;}private static void maxHeapify(int[] array, int i, int size) {int left = 2 * i + 1;int right = 2 * i + 2;int largest = i;if (left < size && array[left] > array[largest]) {largest = left;}if (right < size && array[right] > array[largest]) {largest = right;}if (largest != i) {swap(array, i, largest);maxHeapify(array, largest, size);}}private static void swap(int[] array, int i, int j) {int temp = array[i];array[i] = array[j];array[j] = temp;}@Testvoid contextLoads () {int[] array={34, 21, 13, 2, 5, 1, 55, 3, 1, 8};System.out.println(Arrays.toString(heap_sort(array)));}

5. 输出结果

在这里插入图片描述

6. 算法过程分解

第1次递归
待排序数组如下:
[34, 21, 13, 2, 5, 1, 55, 3, 1, 8]
第1次返回结果:[1, 1, 2, 3, 5, 8, 13, 21, 34]+[55]
第2次递归
待排序数组如下:
[5, 21, 34, 3, 8, 1, 13, 2, 1]
第2次返回结果:[1, 1, 2, 3, 5, 8, 13, 21]+[34]
第3次递归
待排序数组如下:
[1, 5, 21, 3, 8, 1, 13, 2]
第3次返回结果:[1, 1, 2, 3, 5, 8, 13]+[21]
第4次递归
待排序数组如下:
[2, 1, 8, 3, 5, 1, 13]
第4次返回结果:[1, 1, 2, 3, 5, 8]+[13]
第5次递归
待排序数组如下:
[8, 2, 5, 1, 3, 1]
第5次返回结果:[1, 1, 2, 3, 5]+[8]
第6次递归
待排序数组如下:
[1, 3, 5, 1, 2]
第6次返回结果:[1, 1, 2, 3]+[5]
第7次递归
待排序数组如下:
[2, 1, 3, 1]
第7次返回结果:[1, 1, 2]+[3]
第8次递归
待排序数组如下:
[1, 1, 2]
第8次返回结果:[1, 1]+[2]
第9次递归
待排序数组如下:
[1, 1]
第9次返回结果:[1]+[1]
第10次递归
待排序数组如下:
[1]
因为只有一个元素,所以无须排序
第10次返回结果:[1]

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

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

相关文章

C#(C Sharp)学习笔记_数据类型与变量赋值【三】

前言 本期内容会介绍到C#的数据类型&#xff0c;变量和赋值基本操作。当然了&#xff0c;我会简略的讲解常用的数据类型的应用及变量和赋值。 1.数据类型 C#中的数据类型与其他编程语言如出一辙&#xff0c;一下为数据类型参考表。 类型描述范围默认值bool布尔值True 或 Fa…

再谈Redis三种集群模式:主从模式、哨兵模式和Cluster模式

总结经验 redis主从:可实现高并发(读),典型部署方案:一主二从 redis哨兵:可实现高可用,典型部署方案:一主二从三哨兵 redis集群:可同时支持高可用(读与写)、高并发,典型部署方案:三主三从 一、概述 Redis 支持三种集群模式,分别为主从模式、哨兵模式和Cluster模式。…

【学习笔记】Python 环境隔离

文章目录 前言venvvenv 环境管理venv 包管理 virtualenv 以及 virtualenvwrapper安装virtualenvwrapper 环境管理virtualenvwrapper 包管理 condaconda 环境管理conda 包管理 总结参考资料 Python 作为最常用的脚本语言&#xff0c;有着非常丰富的第三方库&#xff0c;但是这也…

YOLOv5改进 | 主干篇 | 反向残差块网络EMO一种轻量级的CNN架构(附完整代码 + 修改教程)

一、本文介绍 本文给大家带来的改进机制是反向残差块网络EMO,其的构成块iRMB在之前我已经发过了,同时进行了二次创新,本文的网络就是由iRMB组成的网络EMO,所以我们二次创新之后的iEMA也可以用于这个网络中,再次形成二次创新,同时本文的主干网络为一种轻量级的CNN架构,在…

redis的数据淘汰测略

Redis 提供了多种数据淘汰策略&#xff0c;可以根据实际需求选择适合的策略。以下是 Redis 中常见的数据淘汰策略&#xff1a; volatile-lru&#xff1a;从已设置过期时间的键中挑选最近最少使用的数据进行淘汰。 volatile-ttl&#xff1a;从已设置过期时间的键中挑选即将过期…

记录在树莓派中部署PI-Assistant开源项目(GPT语音对话)的BUG

核心 在部署PI-Assistant&#xff08;https://github.com/Lucky-183/PI-Assistant&#xff09;项目中&#xff0c;首先要进行环境安装&#xff0c;官网文档中提供的安装命令如下&#xff1a; pip install requests arcade RPi.GPIO pydub numpy wave sounddevice pymysql cn2…

MySql 慢SQL配置,查询,处理

一.慢SQL配置相关 1.查看慢SQL是否开启 执行下面命令查看是否开启慢SQL show variables like %slow_query_log; 复制代码 OFF: 未开启ON: 2.打开慢SQL配置 执行下面的命令开启慢查询日志 set global slow_query_logON; 复制代码 3.修改慢查询阈值 前面介绍了SQL执行到达了…

一个大型系统有哪些组件构成?

一个大型系统有哪些组件构成&#xff1f; 系统设计往往有很多相似之处&#xff0c;但是细节的地方都是独一无二的。那我们可以把系统设计中这些相似的地方抽离出来作为基础组件&#xff0c;让系统设计变成搭积木。接下来&#xff0c;我会把一个系统设计中可以抽离出哪些通用的…

基于RT-Thread(RTT)的HAL库+ADC+DMA多通道采集

前言 在使用到RTT的ADC设备框架进行AD的多通道采集时&#xff0c;发现数据会跳变&#xff0c;觉得可能是没有加DMA的缘故&#xff0c;但RTT好像没有对应的DMA接口函数&#xff08;或者我没找到&#xff09;&#xff0c;故尝试不使用RTT的ADC设备框架&#xff0c;直接使用HAL库…

指针详解(3)

各位少年&#xff0c;大家好&#xff0c;我是博主那一脸阳光&#xff0c;今天介绍 二级指针 指针数组&#xff0c;还有个指针数组模拟二维数组。 前言&#xff1a;在浩瀚的C语言编程宇宙中&#xff0c;指针犹如一把打开内存世界大门的独特钥匙&#xff0c;它不仅是理解程序运行…

实时聊天系统

这个系统可以用于网站的即时通讯&#xff0c;比如客服系统、在线社区等。这个功能不仅对用户友好&#xff0c;而且也是检验技术实现能力的一个很好的案例。 ### 功能概述 该系统允许用户在网站上实时发送和接收消息。为了保持实时性&#xff0c;我们将使用PHP进行服务器端的逻…

React Hooks 学习笔记

1.useState&#xff08;&#xff09; 实现对页面数据的存储&#xff0c;当数据改变时候&#xff0c;自动触发render函数 2.useRef 用来解决两个问题&#xff1a; 1).是获取DOM元素或子组件的实例对象 2).存储渲染周期之间共享的数据 3.useEffect 4.useLayoutEffect 5…

CUDA Cpp正电子发射断层扫描仪校准和图像重建—蒙特卡洛3D伊辛模型

要点 GPU对比CPU计算正弦和&#xff1a;使用单CPU、使用OpenMP库和CUDACUDA并行计算&#xff1a;3D网格运行内核&#xff1a;线程块&#xff0c;线程线性处理3D数组&#xff0c;并行归约&#xff0c;共享内存&#xff0c;矩阵乘法/平铺矩阵乘法&#xff0c;基本线性代数子程序…

Javaweb之SpringBootWeb案例之 @ConfigurationProperties的详细解析

4.3 ConfigurationProperties 讲解完了yml配置文件之后&#xff0c;最后再来介绍一个注解ConfigurationProperties。在介绍注解之前&#xff0c;我们先来看一个场景&#xff0c;分析下代码当中可能存在的问题&#xff1a; 我们在application.properties或者application.yml中配…

图论练习2

内容&#xff1a;路径计数DP&#xff0c;差分约束 最短路计数 题目大意 给一个个点条边的无向无权图&#xff0c;问从出发到其他每个点的最短路有多少条有自环和重边&#xff0c;对答案 解题思路 设边权为1&#xff0c;跑最短路 表示的路径数自环和重边不影…

WPS Office18.7软件日常更新

【应用名称】&#xff1a;WPS Office 【适用平台】&#xff1a;#Android 【软件标签】&#xff1a;#WPS 【应用版本】&#xff1a;18.6.1➡18.7 【应用大小】&#xff1a;160MB 【软件说明】&#xff1a;软件日常更新。WPS Office是使用人数最多的移动办公软件。独有手机阅读模…

正点原子--STM32定时器学习笔记(1)

这部分是笔者对基本定时器的理论知识进行学习与总结&#xff01;&#xff0c;主要记录自己在学习过程中遇到的重难点&#xff0c;其他一些基础点就一笔带过了&#xff01; 1. 定时器概述 1.1 软件定时原理 使用纯软件&#xff08;CPU死等&#xff09;的方式实现定时&#xf…

GetBuffer() 与 ReleaseBuffer() 使用详解

GetBuffer() 与 ReleaseBuffer() 使用详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将深入研究在编程中常用的GetBuffer()与ReleaseBuff…

机器学习_15_贝叶斯算法

文章目录 1 贝叶斯定理相关公式2 朴素贝叶斯算法2.1 朴素贝叶斯算法推导2.2 朴素贝叶斯算法流程 3 高斯朴素贝叶斯4 伯努利朴素贝叶斯5 多项式朴素贝叶斯6 贝叶斯网络6.1 最简单的一个贝叶斯网络6.2 全连接贝叶斯网络6.3 “正常”贝叶斯网络6.4 实际贝叶斯网络&#xff1a;判断…

算法学习——华为机考题库5(HJ31 - HJ35)

算法学习——华为机考题库5&#xff08;HJ31 - HJ35&#xff09; HJ31 单词倒排 描述 对字符串中的所有单词进行倒排。 说明&#xff1a; 1、构成单词的字符只有26个大写或小写英文字母&#xff1b; 2、非构成单词的字符均视为单词间隔符&#xff1b; 3、要求倒排后的单…