十大排序算法之堆排序

堆排序

在简单选择排序文章中,简单选择排序这个“铁憨憨”只顾着自己做比较,并没有将对比较结果进行保存,因此只能一遍遍地重复相同的比较操作,降低了效率。针对这样的操作,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,一经查实,立即删除!

相关文章

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

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

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

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

记录在树莓派中部署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执行到达了…

基于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;它不仅是理解程序运行…

React Hooks 学习笔记

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

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…

机器学习_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、要求倒排后的单…

LeAPI 后端接口开发 - 发布、下线接口

一、上线接口&#xff08;仅管理员&#xff09; 1. 校验请求参数 2. 判断&#xff08;测试&#xff09;接口是否可以调用 引入调用接口的客户端&#xff08;自己写的 SDK&#xff09;注入客户端实例调用接口 3. 修改数据库中接口的状态 /*** 上线&#xff08;发布&#xff…

爬虫(二)

1.同步获取短视频 1.只要播放地址对Json数据解析&#xff0c;先把列表找出&#xff1a; 2.只想要所有的播放地址&#xff0c;通过列表表达式循环遍历这个列表拿到每个对象&#xff0c;再从一个个对象里面找到Video,再从Video里面找到播放地址(play_addr),再从播放地址找到播放…

动态内存管理 智能指针 shared_ptr、unique_ptr、weak_ptr + 定制删除器

动态内存管理常出现的两种问题&#xff1a; 1.忘记释放内存,造成内存泄漏 2.这块内存还有其他指针指向的情况下&#xff0c;就释放了它&#xff0c;会产生引用非法内存的指针&#xff0c;例如 如果类中有属性指向堆区&#xff0c;做赋值操作时会出现浅拷贝的问题 内存泄漏分…

在jetbrains IDEA/Pycharm/Android Studio中安装官方rust插件,开始rust编程

在idea插件市场搜索rust&#xff1a;JetBrains Marketplace &#xff0c;就可以找到rust插件&#xff1a; jetbrains官方rust插件地址&#xff1a;[Deprecated] Rust - IntelliJ IDEs Plugin | Marketplace 直接在idea中搜索rust好像是搜不到的&#xff1a; 需要在这个插件市场…

【数据结构】二叉树链式结构的实现

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 1. 二叉树链式结构的实现1.1 前置说明1.2 二叉树的遍历1.2.1 前序、中序以及后序遍历1.2.2 层序遍历 1.3 节点个数以及高度等1.4 二叉树基础oj练习1.5 二叉树的创建和销毁 1. 二叉树链式结构的实现 1.1 前置说明 在学习二…

Cambalache in Ubuntu

文章目录 前言apt install flatpak这很ok后记 前言 gtkmm4相比gtkmm3有很多改革, 代码也干净了许多, 但在windows上开发 有ui设计器那自然方便很多, 但glade又不支持gtkmm4, windows上装Cambalache很是困难. 各种问题都找不到答案.于是 我用VMware虚拟机Ubuntu20.xx安装Cambal…

macOS虚拟机安装全过程的详细教程

macOS虚拟机安装全过程的详细教程 一、安装虚拟机软件 选择软件&#xff1a;首先&#xff0c;你需要选择一个适合macOS的虚拟机软件。在本教程中&#xff0c;我们以VirtualBox为例。下载与安装&#xff1a;访问VirtualBox的官网&#xff0c;下载适用于macOS的安装包。运行安装…